diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml index f3c00a762b2bc..13f9cc1ab795f 100644 --- a/bom/runtime/pom.xml +++ b/bom/runtime/pom.xml @@ -2230,6 +2230,11 @@ apache-client ${awssdk.version} + + software.amazon.awssdk + url-connection-client + ${awssdk.version} + com.microsoft.azure.functions diff --git a/docs/src/main/asciidoc/dynamodb-guide.adoc b/docs/src/main/asciidoc/dynamodb-guide.adoc index 5897f16987826..8b90fae9bf794 100644 --- a/docs/src/main/asciidoc/dynamodb-guide.adoc +++ b/docs/src/main/asciidoc/dynamodb-guide.adoc @@ -19,7 +19,7 @@ Keep in mind it's actively developed and does not support yet all the features a The Quarkus extension supports two programming models: -* Blocking access using the Apache HTTP Client +* Blocking access using URL Connection HTTP client (by default) or the Apache HTTP Client * https://docs.aws.amazon.com/sdk-for-java/v2/developer-guide/basics-async.html[Asynchronous programming] based on JDK's `CompletableFuture` objects and the Netty HTTP client. In this guide, we see how you can get your REST services to use the DynamoDB locally and on AWS. @@ -318,6 +318,38 @@ The implementation is pretty straightforward and you just need to define your en == Configuring DynamoDB clients Both DynamoDB clients (sync and async) are configurable via the `application.properties` file that can be provided in the `src/main/resources` directory. +Additionally, you need to added to the classpath a proper implementation of the sync client. By default the extension uses URL connection HTTP client, so +you need to add a URL connection client dependency to the `pom.xml` file: + +[source,xml] +---- + + software.amazon.awssdk + url-connection-client + +---- + +If you want to use Apache HTTP client instead, configure it as follows: +[source,properties] +---- +quarkus.dynamodb.sync-client.type=apache +---- + +And add following dependency to the application `pom.xml`: +[source,xml] +---- + + software.amazon.awssdk + apache-client + + + commons-logging + commons-logging + + + +---- +NOTE: It's important to exclude `commons-logging` from the client dependency to force Apache HTTP client to use Quarkus logger. If you're going to use a local DynamoDB instance, configure it as follows: @@ -326,24 +358,24 @@ If you're going to use a local DynamoDB instance, configure it as follows: quarkus.dynamodb.endpoint-override=http://localhost:8000 quarkus.dynamodb.aws.region=eu-central-1 -quarkus.dynamodb.aws.credentials.type=STATIC +quarkus.dynamodb.aws.credentials.type=static quarkus.dynamodb.aws.credentials.static-provider.access-key-id=test-key quarkus.dynamodb.aws.credentials.static-provider.secret-access-key=test-secret ---- - `quarkus.dynamodb.aws.region` - It's required by the client, but since you're using a local DynamoDB instance you can pick any valid AWS region. -- `quarkus.dynamodb.aws.credentials.type` - Set `STATIC` credentials provider with any values for `access-key-id` and `secret-access-key` +- `quarkus.dynamodb.aws.credentials.type` - Set `static` credentials provider with any values for `access-key-id` and `secret-access-key` - `quarkus.dynamodb.endpoint-override` - Override the DynamoDB client to use a local instance instead of an AWS service If you want to work with an AWS account, you'd need to set it with: [source,properties] ---- quarkus.dynamodb.aws.region= -quarkus.dynamodb.aws.credentials.type=DEFAULT +quarkus.dynamodb.aws.credentials.type=default ---- - `quarkus.dynamodb.aws.region` you should set it to the region where you provisioned the DynamoDB table, -- `quarkus.dynamodb.aws.credentials.type` - use the `DEFAULT` credentials provider chain that looks for credentials in this order: +- `quarkus.dynamodb.aws.credentials.type` - use the `default` credentials provider chain that looks for credentials in this order: - Java System Properties - `aws.accessKeyId` and `aws.secretKey` * Environment Variables - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` * Credential profiles file at the default location (`~/.aws/credentials`) shared by all AWS SDKs and the AWS CLI @@ -400,7 +432,7 @@ public class FruitAsyncService extends AbstractService { } ---- -And an asynchronous REST resource: +Create an asynchronous REST resource: [source,java] ---- @@ -445,6 +477,16 @@ public class FruitAsyncResource { } ---- +And add Netty HTTP client dependency to the `pom.xml`: + +[source,xml] +---- + + software.amazon.awssdk + netty-nio-client + +---- + == Configuration Reference include::{generated-dir}/config/quarkus-dynamodb.adoc[opts=optional, leveloffset=+1] diff --git a/extensions/amazon-dynamodb/deployment/pom.xml b/extensions/amazon-dynamodb/deployment/pom.xml index e9d56137a2471..f7e84adbc119d 100644 --- a/extensions/amazon-dynamodb/deployment/pom.xml +++ b/extensions/amazon-dynamodb/deployment/pom.xml @@ -42,6 +42,27 @@ rest-assured test + + software.amazon.awssdk + netty-nio-client + test + + + software.amazon.awssdk + url-connection-client + test + + + software.amazon.awssdk + apache-client + test + + + commons-logging + commons-logging + + + diff --git a/extensions/amazon-dynamodb/deployment/src/main/java/io/quarkus/dynamodb/deployment/DynamodbProcessor.java b/extensions/amazon-dynamodb/deployment/src/main/java/io/quarkus/dynamodb/deployment/DynamodbProcessor.java index 1b1f7f54528d2..6b86aabd8fca4 100644 --- a/extensions/amazon-dynamodb/deployment/src/main/java/io/quarkus/dynamodb/deployment/DynamodbProcessor.java +++ b/extensions/amazon-dynamodb/deployment/src/main/java/io/quarkus/dynamodb/deployment/DynamodbProcessor.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.stream.Collectors; +import javax.enterprise.inject.spi.DeploymentException; + import org.jboss.jandex.DotName; import org.jboss.jandex.Type; @@ -27,19 +29,18 @@ import io.quarkus.deployment.builditem.substrate.SubstrateProxyDefinitionBuildItem; import io.quarkus.deployment.builditem.substrate.SubstrateResourceBuildItem; import io.quarkus.deployment.configuration.ConfigurationError; -import io.quarkus.dynamodb.runtime.ApacheHttpClientConfig; import io.quarkus.dynamodb.runtime.AwsCredentialsProviderType; import io.quarkus.dynamodb.runtime.DynamodbClientProducer; import io.quarkus.dynamodb.runtime.DynamodbConfig; import io.quarkus.dynamodb.runtime.DynamodbRecorder; import io.quarkus.dynamodb.runtime.NettyHttpClientConfig; +import io.quarkus.dynamodb.runtime.SyncHttpClientConfig; +import io.quarkus.dynamodb.runtime.SyncHttpClientConfig.SyncClientType; import io.quarkus.dynamodb.runtime.TlsManagersProviderConfig; import io.quarkus.dynamodb.runtime.TlsManagersProviderType; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.http.SdkHttpService; -import software.amazon.awssdk.http.apache.ApacheSdkHttpService; import software.amazon.awssdk.http.async.SdkAsyncHttpService; -import software.amazon.awssdk.http.nio.netty.NettySdkAsyncHttpService; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.utils.StringUtils; @@ -47,6 +48,10 @@ public class DynamodbProcessor { public static final String AWS_SDK_APPLICATION_ARCHIVE_MARKERS = "software/amazon/awssdk"; + private static final String APACHE_HTTP_SERVICE = "software.amazon.awssdk.http.apache.ApacheSdkHttpService"; + private static final String NETTY_HTTP_SERVICE = "software.amazon.awssdk.http.nio.netty.NettySdkAsyncHttpService"; + private static final String URL_HTTP_SERVICE = "software.amazon.awssdk.http.urlconnection.UrlConnectionSdkHttpService"; + private static final List INTERCEPTOR_PATHS = Arrays.asList( "software/amazon/awssdk/global/handlers/execution.interceptors", "software/amazon/awssdk/services/dynamodb/execution.interceptors"); @@ -112,26 +117,40 @@ DynamodbClientBuildItem analyzeDynamodbClientInjectionPoints(BeanRegistrationPha } if (createSyncClient) { - //Register Apache client as sync client - proxyDefinition - .produce(new SubstrateProxyDefinitionBuildItem("org.apache.http.conn.HttpClientConnectionManager", - "org.apache.http.pool.ConnPoolControl", - "software.amazon.awssdk.http.apache.internal.conn.Wrapped")); - - serviceProvider.produce( - new ServiceProviderBuildItem(SdkHttpService.class.getName(), ApacheSdkHttpService.class.getName())); + if (config.syncClient.type == SyncClientType.APACHE) { + checkClasspath(APACHE_HTTP_SERVICE, "apache-client"); + + //Register Apache client as sync client + proxyDefinition.produce( + new SubstrateProxyDefinitionBuildItem("org.apache.http.conn.HttpClientConnectionManager", + "org.apache.http.pool.ConnPoolControl", + "software.amazon.awssdk.http.apache.internal.conn.Wrapped")); + + serviceProvider.produce(new ServiceProviderBuildItem(SdkHttpService.class.getName(), APACHE_HTTP_SERVICE)); + } else { + checkClasspath(URL_HTTP_SERVICE, "url-connection-client"); + serviceProvider.produce(new ServiceProviderBuildItem(SdkHttpService.class.getName(), URL_HTTP_SERVICE)); + } } if (createAsyncClient) { + checkClasspath(NETTY_HTTP_SERVICE, "netty-nio-client"); //Register netty as async client - serviceProvider.produce( - new ServiceProviderBuildItem(SdkAsyncHttpService.class.getName(), - NettySdkAsyncHttpService.class.getName())); + serviceProvider.produce(new ServiceProviderBuildItem(SdkAsyncHttpService.class.getName(), NETTY_HTTP_SERVICE)); } return new DynamodbClientBuildItem(createSyncClient, createAsyncClient); } + private void checkClasspath(String className, String dependencyName) { + try { + Class.forName(className, true, Thread.currentThread().getContextClassLoader()); + } catch (ClassNotFoundException e) { + throw new DeploymentException( + "Missing 'software.amazon.awssdk:" + dependencyName + "' dependency on the classpath"); + } + } + @BuildStep @Record(ExecutionTime.RUNTIME_INIT) void buildClients(DynamodbClientBuildItem clientBuildItem, DynamodbRecorder recorder, @@ -193,17 +212,19 @@ private static void checkConfig(DynamodbConfig config, List knownInterce } } - private static void checkSyncClientConfig(ApacheHttpClientConfig syncClient) { - if (syncClient.maxConnections <= 0) { - throw new ConfigurationError("quarkus.dynamodb.sync-client.max-connections may not be negative or zero."); - } - if (syncClient.proxy != null && syncClient.proxy.enabled) { - URI proxyEndpoint = syncClient.proxy.endpoint; - if (proxyEndpoint != null) { - validateProxyEndpoint(proxyEndpoint, "sync"); + private static void checkSyncClientConfig(SyncHttpClientConfig syncClient) { + if (syncClient.type == SyncClientType.APACHE) { + if (syncClient.apache.maxConnections <= 0) { + throw new ConfigurationError("quarkus.dynamodb.sync-client.max-connections may not be negative or zero."); + } + if (syncClient.apache.proxy != null && syncClient.apache.proxy.enabled) { + URI proxyEndpoint = syncClient.apache.proxy.endpoint; + if (proxyEndpoint != null) { + validateProxyEndpoint(proxyEndpoint, "sync"); + } } + validateTlsManagersProvider(syncClient.apache.tlsManagersProvider, "sync"); } - validateTlsManagersProvider(syncClient.tlsManagersProvider, "sync"); } private static void checkAsyncClientConfig(NettyHttpClientConfig asyncClient) { diff --git a/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncClientBrokenConfigTest.java b/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncApacheClientBrokenConfigTest.java similarity index 85% rename from extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncClientBrokenConfigTest.java rename to extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncApacheClientBrokenConfigTest.java index 7d441fbb81df2..00c747bc16b35 100644 --- a/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncClientBrokenConfigTest.java +++ b/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncApacheClientBrokenConfigTest.java @@ -12,7 +12,7 @@ import io.quarkus.test.QuarkusUnitTest; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -public class DynamodbSyncClientBrokenConfigTest { +public class DynamodbSyncApacheClientBrokenConfigTest { @Inject DynamoDbClient client; @@ -21,7 +21,7 @@ public class DynamodbSyncClientBrokenConfigTest { static final QuarkusUnitTest config = new QuarkusUnitTest() .setExpectedException(ConfigurationError.class) .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) - .addAsResource("sync-broken-config.properties", "application.properties")); + .addAsResource("sync-apache-broken-config.properties", "application.properties")); @Test public void test() { diff --git a/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncClientBrokenProxyConfigTest.java b/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncApacheClientBrokenProxyConfigTest.java similarity index 83% rename from extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncClientBrokenProxyConfigTest.java rename to extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncApacheClientBrokenProxyConfigTest.java index dbfda30aa76ed..dc786d20a4512 100644 --- a/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncClientBrokenProxyConfigTest.java +++ b/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncApacheClientBrokenProxyConfigTest.java @@ -12,7 +12,7 @@ import io.quarkus.test.QuarkusUnitTest; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -public class DynamodbSyncClientBrokenProxyConfigTest { +public class DynamodbSyncApacheClientBrokenProxyConfigTest { @Inject DynamoDbClient client; @@ -21,7 +21,7 @@ public class DynamodbSyncClientBrokenProxyConfigTest { static final QuarkusUnitTest config = new QuarkusUnitTest() .setExpectedException(ConfigurationError.class) .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) - .addAsResource("sync-broken-proxy-config.properties", "application.properties")); + .addAsResource("sync-apache-broken-proxy-config.properties", "application.properties")); @Test public void test() { diff --git a/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncClientFullConfigTest.java b/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncApacheClientFullConfigTest.java similarity index 81% rename from extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncClientFullConfigTest.java rename to extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncApacheClientFullConfigTest.java index a9a01aea4cb70..e2359f8881ad2 100644 --- a/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncClientFullConfigTest.java +++ b/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncApacheClientFullConfigTest.java @@ -10,7 +10,7 @@ import io.quarkus.test.QuarkusUnitTest; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -public class DynamodbSyncClientFullConfigTest { +public class DynamodbSyncApacheClientFullConfigTest { @Inject DynamoDbClient client; @@ -18,7 +18,7 @@ public class DynamodbSyncClientFullConfigTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) - .addAsResource("sync-full-config.properties", "application.properties")); + .addAsResource("sync-apache-full-config.properties", "application.properties")); @Test public void test() { diff --git a/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncUrlConnClientFullConfigTest.java b/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncUrlConnClientFullConfigTest.java new file mode 100644 index 0000000000000..60f4541539333 --- /dev/null +++ b/extensions/amazon-dynamodb/deployment/src/test/java/io/quarkus/dynamodb/deployment/DynamodbSyncUrlConnClientFullConfigTest.java @@ -0,0 +1,27 @@ +package io.quarkus.dynamodb.deployment; + +import javax.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; + +public class DynamodbSyncUrlConnClientFullConfigTest { + + @Inject + DynamoDbClient client; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addAsResource("sync-urlconn-full-config.properties", "application.properties")); + + @Test + public void test() { + // Application should start with full config. + } +} diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/async-full-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/async-full-config.properties index d11804c004250..90e4f26c69c63 100644 --- a/extensions/amazon-dynamodb/deployment/src/test/resources/async-full-config.properties +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/async-full-config.properties @@ -2,7 +2,7 @@ quarkus.dynamodb.enable-endpoint-discovery=false quarkus.dynamodb.endpoint-override=http://localhost:8000 quarkus.dynamodb.aws.region=us-east-1 -quarkus.dynamodb.aws.credentials.type=STATIC +quarkus.dynamodb.aws.credentials.type=static quarkus.dynamodb.aws.credentials.static-provider.access-key-id=test-key quarkus.dynamodb.aws.credentials.static-provider.secret-access-key=test-secret @@ -15,13 +15,13 @@ quarkus.dynamodb.async-client.connection-acquisition-timeout=0.01S quarkus.dynamodb.async-client.connection-time-to-live=0.01S quarkus.dynamodb.async-client.connection-max-idle-time=0.01S quarkus.dynamodb.async-client.use-idle-connection-reaper=false -quarkus.dynamodb.async-client.protocol = HTTP1_1 +quarkus.dynamodb.async-client.protocol = http1-1 quarkus.dynamodb.async-client.max-http2-streams = 10 -quarkus.dynamodb.async-client.ssl-provider = JDK +quarkus.dynamodb.async-client.ssl-provider = jdk quarkus.dynamodb.async-client.event-loop.override = true quarkus.dynamodb.async-client.event-loop.number-of-threads = 5 quarkus.dynamodb.async-client.event-loop.thread-name-prefix = Quarkus-Netty-EventLoop- quarkus.dynamodb.async-client.proxy.enabled = true quarkus.dynamodb.async-client.proxy.endpoint = http://127.1.1.1 quarkus.dynamodb.async-client.proxy.non-proxy-hosts = localhost, hostlocal -quarkus.dynamodb.async-client.tls-managers-provider.type=SYSTEM_PROPERTY \ No newline at end of file +quarkus.dynamodb.async-client.tls-managers-provider.type=system-property \ No newline at end of file diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/async-tls-filestore-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/async-tls-filestore-config.properties index 4c69f6fe61257..65ffaa596619f 100644 --- a/extensions/amazon-dynamodb/deployment/src/test/resources/async-tls-filestore-config.properties +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/async-tls-filestore-config.properties @@ -1,6 +1,6 @@ quarkus.dynamodb.aws.region=us-east-1 -quarkus.dynamodb.async-client.tls-managers-provider.type=FILE_STORE +quarkus.dynamodb.async-client.tls-managers-provider.type=file-store quarkus.dynamodb.async-client.tls-managers-provider.file-store.path=/tmp/file.key quarkus.dynamodb.async-client.tls-managers-provider.file-store.type=pkcs11 quarkus.dynamodb.async-client.tls-managers-provider.file-store.password=thePassword \ No newline at end of file diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/default-credentials-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/default-credentials-config.properties index 33ffae4072d2d..8a7fad0a7de21 100644 --- a/extensions/amazon-dynamodb/deployment/src/test/resources/default-credentials-config.properties +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/default-credentials-config.properties @@ -1,6 +1,6 @@ quarkus.dynamodb.aws.region=us-east-2 -quarkus.dynamodb.aws.credentials.type=DEFAULT +quarkus.dynamodb.aws.credentials.type=default quarkus.dynamodb.aws.credentials.default-provider.async-credential-update-enabled=true quarkus.dynamodb.aws.credentials.default-provider.reuse-last-provider-enabled=true diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/process-credentials-broken-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/process-credentials-broken-config.properties index 92f9bbe05864e..84fedaa7dfdf7 100644 --- a/extensions/amazon-dynamodb/deployment/src/test/resources/process-credentials-broken-config.properties +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/process-credentials-broken-config.properties @@ -1,2 +1,2 @@ -quarkus.dynamodb.aws.credentials.type=PROCESS +quarkus.dynamodb.aws.credentials.type=process diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/profile-credentials-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/profile-credentials-config.properties index f565b1bf64b59..2ea33444d9cb1 100644 --- a/extensions/amazon-dynamodb/deployment/src/test/resources/profile-credentials-config.properties +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/profile-credentials-config.properties @@ -1,5 +1,5 @@ quarkus.dynamodb.aws.region=us-east-2 -quarkus.dynamodb.aws.credentials.type=PROFILE +quarkus.dynamodb.aws.credentials.type=profile quarkus.dynamodb.aws.credentials.profile-provider.profile-name=myprofile diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/static-credentials-broken-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/static-credentials-broken-config.properties index 8603551e320c5..72eb83daa3681 100644 --- a/extensions/amazon-dynamodb/deployment/src/test/resources/static-credentials-broken-config.properties +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/static-credentials-broken-config.properties @@ -1 +1 @@ -quarkus.dynamodb.aws.credentials.type=STATIC \ No newline at end of file +quarkus.dynamodb.aws.credentials.type=static \ No newline at end of file diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-apache-broken-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-apache-broken-config.properties new file mode 100644 index 0000000000000..2c5b0fc5861f2 --- /dev/null +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-apache-broken-config.properties @@ -0,0 +1,4 @@ +quarkus.dynamodb.sync-client.type = apache +quarkus.dynamodb.sync-client.apache.max-connections = -10 + + diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-apache-broken-proxy-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-apache-broken-proxy-config.properties new file mode 100644 index 0000000000000..502389b51e71c --- /dev/null +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-apache-broken-proxy-config.properties @@ -0,0 +1,6 @@ +quarkus.dynamodb.sync-client.type = apache +quarkus.dynamodb.sync-client.apache.proxy.enabled = true +quarkus.dynamodb.sync-client.apache.proxy.endpoint = http://user:name@127.1.1.1?foo=bar + + + diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-apache-full-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-apache-full-config.properties new file mode 100644 index 0000000000000..eba7c04311468 --- /dev/null +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-apache-full-config.properties @@ -0,0 +1,28 @@ +quarkus.dynamodb.enable-endpoint-discovery=false +quarkus.dynamodb.endpoint-override=http://localhost:8000 + +quarkus.dynamodb.aws.region=us-east-2 +quarkus.dynamodb.aws.credentials.type=static +quarkus.dynamodb.aws.credentials.static-provider.access-key-id=test-key +quarkus.dynamodb.aws.credentials.static-provider.secret-access-key=test-secret + +quarkus.dynamodb.sync-client.type=apache +quarkus.dynamodb.sync-client.socket-timeout = 0.100S +quarkus.dynamodb.sync-client.connection-timeout = 0.100S + +quarkus.dynamodb.sync-client.apache.connection-acquisition-timeout = 0.100S +quarkus.dynamodb.sync-client.apache.connection-max-idle-time = 0.100S +quarkus.dynamodb.sync-client.apache.connection-time-to-live = 0.100S +quarkus.dynamodb.sync-client.apache.max-connections = 10 +quarkus.dynamodb.sync-client.apache.expect-continue-enabled = true +quarkus.dynamodb.sync-client.apache.use-idle-connection-reaper = true +quarkus.dynamodb.sync-client.apache.proxy.enabled = true +quarkus.dynamodb.sync-client.apache.proxy.endpoint = http://127.1.1.1 +quarkus.dynamodb.sync-client.apache.proxy.username = foo +quarkus.dynamodb.sync-client.apache.proxy.password = bar +quarkus.dynamodb.sync-client.apache.proxy.ntlm-domain = foo-domainn +quarkus.dynamodb.sync-client.apache.proxy.ntlm-workstation = foo-workstation +quarkus.dynamodb.sync-client.apache.proxy.preemptive-basic-authentication-enabled = true +quarkus.dynamodb.sync-client.apache.proxy.non-proxy-hosts = localhost, hostlocal +quarkus.dynamodb.sync-client.apache.tls-managers-provider.type=system-property + diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-broken-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-broken-config.properties deleted file mode 100644 index 59f15da63db07..0000000000000 --- a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-broken-config.properties +++ /dev/null @@ -1,3 +0,0 @@ -quarkus.dynamodb.sync-client.max-connections = -10 - - diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-broken-proxy-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-broken-proxy-config.properties deleted file mode 100644 index 7c2cbb0657ab5..0000000000000 --- a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-broken-proxy-config.properties +++ /dev/null @@ -1,5 +0,0 @@ -quarkus.dynamodb.sync-client.proxy.enabled = true -quarkus.dynamodb.sync-client.proxy.endpoint = http://user:name@127.1.1.1?foo=bar - - - diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-full-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-full-config.properties deleted file mode 100644 index 6e2d315e514ec..0000000000000 --- a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-full-config.properties +++ /dev/null @@ -1,26 +0,0 @@ -quarkus.dynamodb.enable-endpoint-discovery=false -quarkus.dynamodb.endpoint-override=http://localhost:8000 - -quarkus.dynamodb.aws.region=us-east-2 -quarkus.dynamodb.aws.credentials.type=STATIC -quarkus.dynamodb.aws.credentials.static-provider.access-key-id=test-key -quarkus.dynamodb.aws.credentials.static-provider.secret-access-key=test-secret - -quarkus.dynamodb.sync-client.connection-acquisition-timeout = 0.100S -quarkus.dynamodb.sync-client.connection-max-idle-time = 0.100S -quarkus.dynamodb.sync-client.connection-timeout = 0.100S -quarkus.dynamodb.sync-client.connection-time-to-live = 0.100S -quarkus.dynamodb.sync-client.socket-timeout = 0.100S -quarkus.dynamodb.sync-client.max-connections = 10 -quarkus.dynamodb.sync-client.expect-continue-enabled = true -quarkus.dynamodb.sync-client.use-idle-connection-reaper = true -quarkus.dynamodb.sync-client.proxy.enabled = true -quarkus.dynamodb.sync-client.proxy.endpoint = http://127.1.1.1 -quarkus.dynamodb.sync-client.proxy.username = foo -quarkus.dynamodb.sync-client.proxy.password = bar -quarkus.dynamodb.sync-client.proxy.ntlm-domain = foo-domainn -quarkus.dynamodb.sync-client.proxy.ntlm-workstation = foo-workstation -quarkus.dynamodb.sync-client.proxy.preemptive-basic-authentication-enabled = true -quarkus.dynamodb.sync-client.proxy.non-proxy-hosts = localhost, hostlocal -quarkus.dynamodb.sync-client.tls-managers-provider.type=SYSTEM_PROPERTY - diff --git a/extensions/amazon-dynamodb/deployment/src/test/resources/sync-urlconn-full-config.properties b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-urlconn-full-config.properties new file mode 100644 index 0000000000000..50bddab66d55f --- /dev/null +++ b/extensions/amazon-dynamodb/deployment/src/test/resources/sync-urlconn-full-config.properties @@ -0,0 +1,13 @@ +quarkus.dynamodb.enable-endpoint-discovery=false +quarkus.dynamodb.endpoint-override=http://localhost:8000 + +quarkus.dynamodb.aws.region=us-east-2 +quarkus.dynamodb.aws.credentials.type=static +quarkus.dynamodb.aws.credentials.static-provider.access-key-id=test-key +quarkus.dynamodb.aws.credentials.static-provider.secret-access-key=test-secret + +quarkus.dynamodb.sync-client.type=url +quarkus.dynamodb.sync-client.socket-timeout=0.100S +quarkus.dynamodb.sync-client.connection-timeout=0.100S + + diff --git a/extensions/amazon-dynamodb/runtime/pom.xml b/extensions/amazon-dynamodb/runtime/pom.xml index 57e3218351361..916fbc0317585 100644 --- a/extensions/amazon-dynamodb/runtime/pom.xml +++ b/extensions/amazon-dynamodb/runtime/pom.xml @@ -35,10 +35,17 @@ software.amazon.awssdk netty-nio-client + true + + + software.amazon.awssdk + url-connection-client + true software.amazon.awssdk apache-client + true commons-logging diff --git a/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/ApacheHttpClientConfig.java b/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/ApacheHttpClientConfig.java deleted file mode 100644 index c7304e570f224..0000000000000 --- a/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/ApacheHttpClientConfig.java +++ /dev/null @@ -1,135 +0,0 @@ -package io.quarkus.dynamodb.runtime; - -import java.net.URI; -import java.time.Duration; -import java.util.List; -import java.util.Optional; - -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; - -@ConfigGroup -public class ApacheHttpClientConfig { - - /** - * The maximum amount of time to establish a connection before timing out. - */ - @ConfigItem(defaultValue = "2S") - public Duration connectionTimeout; - - /** - * The amount of time to wait when acquiring a connection from the pool before giving up and timing out. - */ - @ConfigItem(defaultValue = "10S") - public Duration connectionAcquisitionTimeout; - - /** - * The maximum amount of time that a connection should be allowed to remain open while idle. - */ - @ConfigItem(defaultValue = "60S") - public Duration connectionMaxIdleTime; - - /** - * The maximum amount of time that a connection should be allowed to remain open, regardless of usage frequency. - */ - @ConfigItem - public Optional connectionTimeToLive; - - /** - * The amount of time to wait for data to be transferred over an established, open connection before the connection is timed - * out. - */ - @ConfigItem(defaultValue = "30S") - public Duration socketTimeout; - - /** - * The maximum number of connections allowed in the connection pool. - *

- * Each built HTTP client has its own private connection pool. - */ - @ConfigItem(defaultValue = "50") - public int maxConnections; - - /** - * Whether the client should send an HTTP expect-continue handshake before each request. - */ - @ConfigItem(defaultValue = "true") - public boolean expectContinueEnabled; - - /** - * Whether the idle connections in the connection pool should be closed asynchronously. - *

- * When enabled, connections left idling for longer than `quarkus.dynamodb.sync-client.connection-max-idle-time` will be - * closed. - * This will not close connections currently in use. - */ - @ConfigItem(defaultValue = "true") - public boolean useIdleConnectionReaper; - - /** - * HTTP proxy configuration - */ - @ConfigItem - public HttpClientProxyConfiguration proxy; - - /** - * TLS Managers provider configuration - */ - @ConfigItem - public TlsManagersProviderConfig tlsManagersProvider; - - @ConfigGroup - public static class HttpClientProxyConfiguration { - - /** - * Enable HTTP proxy - */ - @ConfigItem - public boolean enabled; - - /** - * The endpoint of the proxy server that the SDK should connect through. - *

- * Currently, the endpoint is limited to a host and port. Any other URI components will result in an exception being - * raised. - */ - @ConfigItem - public URI endpoint; - - /** - * The username to use when connecting through a proxy. - */ - @ConfigItem - public Optional username; - - /** - * The password to use when connecting through a proxy. - */ - @ConfigItem - public Optional password; - - /** - * For NTLM proxies - the Windows domain name to use when authenticating with the proxy. - */ - @ConfigItem - public Optional ntlmDomain; - - /** - * For NTLM proxies - the Windows workstation name to use when authenticating with the proxy. - */ - @ConfigItem - public Optional ntlmWorkstation; - - /** - * Whether to attempt to authenticate preemptively against the proxy server using basic authentication. - */ - @ConfigItem - public Optional preemptiveBasicAuthenticationEnabled; - - /** - * The hosts that the client is allowed to access without going through the proxy. - */ - @ConfigItem - public List nonProxyHosts; - } -} diff --git a/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/DynamodbClientProducer.java b/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/DynamodbClientProducer.java index e51af99d30a4d..940aa53c93cb5 100644 --- a/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/DynamodbClientProducer.java +++ b/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/DynamodbClientProducer.java @@ -11,9 +11,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import io.quarkus.dynamodb.runtime.SyncHttpClientConfig.SyncClientType; import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder; import software.amazon.awssdk.core.client.builder.SdkClientBuilder; -import software.amazon.awssdk.core.client.builder.SdkSyncClientBuilder; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.http.apache.ApacheHttpClient; @@ -21,6 +21,7 @@ import software.amazon.awssdk.http.apache.ProxyConfiguration; import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient; import software.amazon.awssdk.http.nio.netty.SdkEventLoopGroup; +import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClientBuilder; import software.amazon.awssdk.services.dynamodb.DynamoDbBaseClientBuilder; @@ -101,40 +102,54 @@ private void initSdkClient(SdkClientBuilder builder, SdkConfig config) { } } - private void initHttpClient(SdkSyncClientBuilder builder, ApacheHttpClientConfig config) { - builder.httpClientBuilder(createApacheClientBuilder(config)); + private void initHttpClient(DynamoDbClientBuilder builder, SyncHttpClientConfig config) { + if (config.type == SyncClientType.APACHE) { + builder.httpClientBuilder(createApacheClientBuilder(config)); + } else { + builder.httpClientBuilder(createUrlConnectionClientBuilder(config)); + } } private void initHttpClient(DynamoDbAsyncClientBuilder builder, NettyHttpClientConfig config) { builder.httpClientBuilder(createNettyClientBuilder(config)); } - private ApacheHttpClient.Builder createApacheClientBuilder(ApacheHttpClientConfig config) { + private UrlConnectionHttpClient.Builder createUrlConnectionClientBuilder(SyncHttpClientConfig config) { + UrlConnectionHttpClient.Builder builder = UrlConnectionHttpClient.builder(); + builder.connectionTimeout(config.connectionTimeout); + builder.socketTimeout(config.socketTimeout); + return builder; + } + + private ApacheHttpClient.Builder createApacheClientBuilder(SyncHttpClientConfig config) { Builder builder = ApacheHttpClient.builder(); builder.connectionTimeout(config.connectionTimeout); - builder.connectionAcquisitionTimeout(config.connectionAcquisitionTimeout); - builder.connectionMaxIdleTime(config.connectionMaxIdleTime); - config.connectionTimeToLive.ifPresent(builder::connectionTimeToLive); - builder.expectContinueEnabled(config.expectContinueEnabled); - builder.maxConnections(config.maxConnections); builder.socketTimeout(config.socketTimeout); - builder.useIdleConnectionReaper(config.useIdleConnectionReaper); - if (config.proxy.enabled) { - ProxyConfiguration.Builder proxyBuilder = ProxyConfiguration.builder().endpoint(config.proxy.endpoint); - config.proxy.username.ifPresent(proxyBuilder::username); - config.proxy.password.ifPresent(proxyBuilder::password); - config.proxy.nonProxyHosts.forEach(proxyBuilder::addNonProxyHost); - config.proxy.ntlmDomain.ifPresent(proxyBuilder::ntlmDomain); - config.proxy.ntlmWorkstation.ifPresent(proxyBuilder::ntlmWorkstation); - config.proxy.preemptiveBasicAuthenticationEnabled + builder.connectionAcquisitionTimeout(config.apache.connectionAcquisitionTimeout); + builder.connectionMaxIdleTime(config.apache.connectionMaxIdleTime); + config.apache.connectionTimeToLive.ifPresent(builder::connectionTimeToLive); + builder.expectContinueEnabled(config.apache.expectContinueEnabled); + builder.maxConnections(config.apache.maxConnections); + builder.useIdleConnectionReaper(config.apache.useIdleConnectionReaper); + + if (config.apache.proxy.enabled) { + ProxyConfiguration.Builder proxyBuilder = ProxyConfiguration.builder() + .endpoint(config.apache.proxy.endpoint); + config.apache.proxy.username.ifPresent(proxyBuilder::username); + config.apache.proxy.password.ifPresent(proxyBuilder::password); + config.apache.proxy.nonProxyHosts.forEach(proxyBuilder::addNonProxyHost); + config.apache.proxy.ntlmDomain.ifPresent(proxyBuilder::ntlmDomain); + config.apache.proxy.ntlmWorkstation.ifPresent(proxyBuilder::ntlmWorkstation); + config.apache.proxy.preemptiveBasicAuthenticationEnabled .ifPresent(proxyBuilder::preemptiveBasicAuthenticationEnabled); builder.proxyConfiguration(proxyBuilder.build()); } - builder.tlsKeyManagersProvider(config.tlsManagersProvider.type.create(config.tlsManagersProvider)); + builder.tlsKeyManagersProvider( + config.apache.tlsManagersProvider.type.create(config.apache.tlsManagersProvider)); return builder; } diff --git a/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/DynamodbConfig.java b/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/DynamodbConfig.java index 2cc94c57b21e2..385dc2125247f 100644 --- a/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/DynamodbConfig.java +++ b/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/DynamodbConfig.java @@ -26,10 +26,10 @@ public class DynamodbConfig { public AwsConfig aws; /** - * Apache HTTP client transport configuration + * Sync client transport configuration */ @ConfigItem - public ApacheHttpClientConfig syncClient; + public SyncHttpClientConfig syncClient; /** * Netty HTTP client transport configuration diff --git a/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/SyncHttpClientConfig.java b/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/SyncHttpClientConfig.java new file mode 100644 index 0000000000000..f1cabe0217d2b --- /dev/null +++ b/extensions/amazon-dynamodb/runtime/src/main/java/io/quarkus/dynamodb/runtime/SyncHttpClientConfig.java @@ -0,0 +1,157 @@ +package io.quarkus.dynamodb.runtime; + +import java.net.URI; +import java.time.Duration; +import java.util.List; +import java.util.Optional; + +import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigItem; + +@ConfigGroup +public class SyncHttpClientConfig { + + /** + * Type of the sync HTTP client implementation + */ + @ConfigItem(defaultValue = "url") + public SyncClientType type; + + /** + * The maximum amount of time to establish a connection before timing out. + */ + @ConfigItem(defaultValue = "2S") + public Duration connectionTimeout; + + /** + * The amount of time to wait for data to be transferred over an established, open connection before the connection is + * timed + * out. + */ + @ConfigItem(defaultValue = "30S") + public Duration socketTimeout; + + /** + * Apache HTTP client additional configuration + */ + @ConfigItem + public ApacheHttpClientConfig apache; + + @ConfigGroup + public static class ApacheHttpClientConfig { + + /** + * The amount of time to wait when acquiring a connection from the pool before giving up and timing out. + */ + @ConfigItem(defaultValue = "10S") + public Duration connectionAcquisitionTimeout; + + /** + * The maximum amount of time that a connection should be allowed to remain open while idle. + */ + @ConfigItem(defaultValue = "60S") + public Duration connectionMaxIdleTime; + + /** + * The maximum amount of time that a connection should be allowed to remain open, regardless of usage frequency. + */ + @ConfigItem + public Optional connectionTimeToLive; + + /** + * The maximum number of connections allowed in the connection pool. + *

+ * Each built HTTP client has its own private connection pool. + */ + @ConfigItem(defaultValue = "50") + public int maxConnections; + + /** + * Whether the client should send an HTTP expect-continue handshake before each request. + */ + @ConfigItem(defaultValue = "true") + public boolean expectContinueEnabled; + + /** + * Whether the idle connections in the connection pool should be closed asynchronously. + *

+ * When enabled, connections left idling for longer than `quarkus.dynamodb.sync-client.connection-max-idle-time` will be + * closed. + * This will not close connections currently in use. + */ + @ConfigItem(defaultValue = "true") + public boolean useIdleConnectionReaper; + + /** + * HTTP proxy configuration + */ + @ConfigItem + public HttpClientProxyConfiguration proxy; + + /** + * TLS Managers provider configuration + */ + @ConfigItem + public TlsManagersProviderConfig tlsManagersProvider; + + @ConfigGroup + public static class HttpClientProxyConfiguration { + + /** + * Enable HTTP proxy + */ + @ConfigItem + public boolean enabled; + + /** + * The endpoint of the proxy server that the SDK should connect through. + *

+ * Currently, the endpoint is limited to a host and port. Any other URI components will result in an exception being + * raised. + */ + @ConfigItem + public URI endpoint; + + /** + * The username to use when connecting through a proxy. + */ + @ConfigItem + public Optional username; + + /** + * The password to use when connecting through a proxy. + */ + @ConfigItem + public Optional password; + + /** + * For NTLM proxies - the Windows domain name to use when authenticating with the proxy. + */ + @ConfigItem + public Optional ntlmDomain; + + /** + * For NTLM proxies - the Windows workstation name to use when authenticating with the proxy. + */ + @ConfigItem + public Optional ntlmWorkstation; + + /** + * Whether to attempt to authenticate preemptively against the proxy server using basic authentication. + */ + @ConfigItem + public Optional preemptiveBasicAuthenticationEnabled; + + /** + * The hosts that the client is allowed to access without going through the proxy. + */ + @ConfigItem + public List nonProxyHosts; + } + } + + public enum SyncClientType { + URL, + APACHE + } +} diff --git a/integration-tests/amazon-dynamodb/pom.xml b/integration-tests/amazon-dynamodb/pom.xml index 0cdcc82c56583..51f0a5da3f347 100644 --- a/integration-tests/amazon-dynamodb/pom.xml +++ b/integration-tests/amazon-dynamodb/pom.xml @@ -37,6 +37,15 @@ quarkus-amazon-dynamodb + + software.amazon.awssdk + netty-nio-client + + + software.amazon.awssdk + url-connection-client + + org.jboss.slf4j slf4j-jboss-logging @@ -49,11 +58,6 @@ quarkus-junit5 test - - org.glassfish - javax.json - test - io.rest-assured rest-assured diff --git a/integration-tests/amazon-dynamodb/src/main/resources/application.properties b/integration-tests/amazon-dynamodb/src/main/resources/application.properties index 1f38bea809410..0e1f4ad6a82b5 100644 --- a/integration-tests/amazon-dynamodb/src/main/resources/application.properties +++ b/integration-tests/amazon-dynamodb/src/main/resources/application.properties @@ -1,8 +1,8 @@ quarkus.dynamodb.endpoint-override=${dynamodb.url} quarkus.dynamodb.aws.region=eu-central-1 -quarkus.dynamodb.aws.credentials.type=STATIC +quarkus.dynamodb.aws.credentials.type=static quarkus.dynamodb.aws.credentials.static-provider.access-key-id=test-key quarkus.dynamodb.aws.credentials.static-provider.secret-access-key=test-secret -quarkus.dynamodb.interceptors=io.quarkus.it.dynamodb.DynamoDBModifyResponse \ No newline at end of file +quarkus.dynamodb.interceptors=io.quarkus.it.dynamodb.DynamoDBModifyResponse