AWS SDK2 - Dynamodb extension

This commit is contained in:
Marcin Czeczko
2019-04-25 11:42:03 +02:00
parent 3539c4d073
commit 3e0706b2af
18 changed files with 863 additions and 1 deletions

View File

@@ -36,11 +36,14 @@ jobs:
- script: docker run --rm --publish 5432:5432 --name build-postgres -e POSTGRES_USER=hibernate_orm_test -e POSTGRES_PASSWORD=hibernate_orm_test -e POSTGRES_DB=hibernate_orm_test -d postgres:10.5
displayName: 'start postgres'
- script: docker run --rm --publish 8000:8000 --name build-dynamodb -d amazon/dynamodb-local:1.11.477
displayName: 'start dynamodb'
- task: Maven@3
displayName: 'Maven Build'
inputs:
goals: 'install'
options: '-B --settings azure-mvn-settings.xml -Dnative-image.docker-build -Dtest-postgresql -Dtest-elasticsearch -Dnative-image.xmx=6g -Dnative -Dno-format'
options: '-B --settings azure-mvn-settings.xml -Dnative-image.docker-build -Dtest-postgresql -Dtest-elasticsearch -Dtest-dynamodb -Ddynamodb-local.port=8000 -Dnative-image.xmx=6g -Dnative -Dno-format'
- job: Windows_Build
timeoutInMinutes: 60

View File

@@ -71,6 +71,7 @@
<jackson.version>2.9.9</jackson.version>
<commons-beanutils.version>1.9.3</commons-beanutils.version>
<commons-logging.version>1.2</commons-logging.version>
<commons-logging-jboss-logging.version>1.0.0.Final</commons-logging-jboss-logging.version>
<commons-lang3.version>3.8.1</commons-lang3.version>
<commons-codec.version>1.11</commons-codec.version>
<validation-api.version>2.0.1.Final</validation-api.version>
@@ -130,6 +131,7 @@
<aws-lambda-java.version>1.1.0</aws-lambda-java.version>
<aws-lambda-java-events.version>2.2.5</aws-lambda-java-events.version>
<aws-lambda-serverless-java-container.version>1.3.1</aws-lambda-serverless-java-container.version>
<awssdk.version>2.7.0</awssdk.version>
<kotlin.version>1.3.31</kotlin.version>
<camel.version>3.0.0-M2</camel.version>
<dekorate.version>0.6.1</dekorate.version>
@@ -519,6 +521,11 @@
<artifactId>quarkus-amazon-lambda-resteasy</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-dynamodb</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes</artifactId>
@@ -683,6 +690,11 @@
<artifactId>jboss-logging</artifactId>
<version>${jboss-logging.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>commons-logging-jboss-logging</artifactId>
<version>${commons-logging-jboss-logging.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logmanager</groupId>
<artifactId>jboss-logmanager-embedded</artifactId>
@@ -1932,6 +1944,22 @@
<version>${aws-lambda-serverless-java-container.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb</artifactId>
<version>${awssdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
<version>${awssdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
<version>${awssdk.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-artifact-transfer</artifactId>

View File

@@ -686,6 +686,16 @@
<artifactId>quarkus-amazon-lambda-resteasy-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-dynamodb</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-dynamodb-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kotlin</artifactId>
@@ -795,6 +805,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-dynamodb</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>

View File

@@ -20,6 +20,7 @@ public final class FeatureBuildItem extends MultiBuildItem {
public static final String CAMEL_SALESFORCE = "camel-salesforce";
public static final String CAMEL_SERVLET = "camel-servlet";
public static final String CDI = "cdi";
public static final String DYNAMODB = "dynamodb";
public static final String ELASTICSEARCH_REST_CLIENT = "elasticsearch-rest-client";
public static final String FLYWAY = "flyway";
public static final String HIBERNATE_ORM = "hibernate-orm";

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>io.quarkus</groupId>
<artifactId>quarkus-amazon-dynamodb-parent</artifactId>
<version>999-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>quarkus-amazon-dynamodb-deployment</artifactId>
<name>Quarkus - Amazon DynamoDB - Deployment</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-netty-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-dynamodb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,52 @@
package io.quarkus.dynamodb.deployment;
import javax.inject.Inject;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.substrate.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.substrate.ServiceProviderBuildItem;
import io.quarkus.deployment.builditem.substrate.SubstrateProxyDefinitionBuildItem;
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;
public class DynamodbProcessor {
public static final String AWS_SDK_APPLICATION_ARCHIVE_MARKERS = "software/amazon/awssdk";
@Inject
BuildProducer<ExtensionSslNativeSupportBuildItem> extensionSslNativeSupport;
@BuildStep
void build(BuildProducer<FeatureBuildItem> feature) {
feature.produce(new FeatureBuildItem(FeatureBuildItem.DYNAMODB));
}
@BuildStep
void setupDynamoDb() {
// Indicates that this extension would like the SSL support to be enabled
extensionSslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(FeatureBuildItem.DYNAMODB));
}
@BuildStep
SubstrateProxyDefinitionBuildItem httpProxies() {
return new SubstrateProxyDefinitionBuildItem("org.apache.http.conn.HttpClientConnectionManager",
"org.apache.http.pool.ConnPoolControl", "software.amazon.awssdk.http.apache.internal.conn.Wrapped");
}
@BuildStep(applicationArchiveMarkers = { AWS_SDK_APPLICATION_ARCHIVE_MARKERS })
void setupSdkAsyncHttpService(BuildProducer<ServiceProviderBuildItem> serviceProvider,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
//Register netty as async client
serviceProvider.produce(
new ServiceProviderBuildItem(SdkAsyncHttpService.class.getName(), NettySdkAsyncHttpService.class.getName()));
//Register Apache client as sync client
serviceProvider.produce(
new ServiceProviderBuildItem(SdkHttpService.class.getName(), ApacheSdkHttpService.class.getName()));
}
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>quarkus-build-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../../build-parent/pom.xml</relativePath>
</parent>
<artifactId>quarkus-amazon-dynamodb-parent</artifactId>
<name>Quarkus - Amazon DynamoDB</name>
<packaging>pom</packaging>
<modules>
<module>runtime</module>
<module>deployment</module>
</modules>
</project>

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>io.quarkus</groupId>
<artifactId>quarkus-amazon-dynamodb-parent</artifactId>
<version>999-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>quarkus-amazon-dynamodb</artifactId>
<name>Quarkus - Amazon DynamoDB - Runtime</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-netty</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>commons-logging-jboss-logging</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bootstrap-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -86,6 +86,7 @@
<!-- Integrations -->
<module>amazon-lambda</module>
<module>amazon-lambda-resteasy</module>
<module>amazon-dynamodb</module>
<!-- Camel -->
<module>camel</module>

View File

@@ -0,0 +1,38 @@
# Example with AWS DynamoDB
## Running the tests
By default, the tests of this module are disabled.
To run the tests in a standard JVM with DynamoDB started as a Docker container, you can run the following command:
```
mvn clean install -Dtest-dynamodb -Ddocker
```
Additionally, you can generate a native image and run the tests for this native image by adding `-Dnative`:
```
mvn clean install -Dtest-dynamodb -Ddocker -Dnative
```
If you don't want to run DynamoDB as a Docker container, you can start your own [DynamoDB local server](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html) on any port.
Then you can define a specific connection URL with `-Ddynamodb-local.port=8888`
You can then run the tests as follows (either with `-Dnative` or not):
```
mvn clean install -Dtest-dynamodb -Ddynamodb-local.port=8888
```
Alternatively, you can run the tests against your AWS account.
AWS access key ID and secret key set to your AWS account set as environment variables
```
export AWS_ACCESS_KEY_ID='YOUR_KEY'
export AWS_SECRET_ACCESS_KEY='YOUR_SECRET_KEY'
```
You can then run the tests as follows (either with `-Dnative` or not):
```
mvn clean install -Dtest-dynamodb -Ddynamodb.aws=true
```

View File

@@ -0,0 +1,255 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-integration-tests-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>quarkus-integration-test-amazon-dynamodb</artifactId>
<name>Quarkus - Integration Tests - AWS DynamoDB</name>
<description>The AWS DynamoDB integration tests</description>
<properties>
<dynamodb.aws>false</dynamodb.aws>
</properties>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-dynamodb</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.slf4j</groupId>
<artifactId>slf4j-jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>${project.groupId}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>test-dynamodb</id>
<activation>
<property>
<name>test-dynamodb</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>reserve-network-port</id>
<goals>
<goal>reserve-network-port</goal>
</goals>
<phase>initialize</phase>
<configuration>
<portNames>
<portName>dynamodb-local.port</portName>
</portNames>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>false</skip>
<argLine>-Ddynamodb.port=${dynamodb-local.port}</argLine>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>native-image</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<environmentVariables>
<DYNAMODB_PORT>${dynamodb-local.port}</DYNAMODB_PORT>
<DYNAMODB_AWS>${dynamodb.aws}</DYNAMODB_AWS>
</environmentVariables>
<systemProperties>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>${project.groupId}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<id>native-image</id>
<goals>
<goal>native-image</goal>
</goals>
<configuration>
<reportErrorsAtRuntime>false</reportErrorsAtRuntime>
<cleanupServer>true</cleanupServer>
<enableHttpUrlHandler>true</enableHttpUrlHandler>
<enableServer>false</enableServer>
<dumpProxies>false</dumpProxies>
<graalvmHome>${graalvmHome}</graalvmHome>
<enableJni>true</enableJni>
<enableAllSecurityServices>true</enableAllSecurityServices>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>docker-dynamodb</id>
<activation>
<property>
<name>docker</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<images>
<image>
<name>amazon/dynamodb-local:1.11.477</name>
<alias>dynamodb-local</alias>
<run>
<ports>
<port>${dynamodb-local.port}:8000</port>
</ports>
<wait>
<http>
<url>http://localhost:${dynamodb-local.port}/shell/</url>
</http>
<time>10000</time>
</wait>
</run>
</image>
</images>
<!--Stops all dynamodb images currently running, not just those we just started.
Useful to stop processes still running from a previously failed integration test run -->
<allContainers>true</allContainers>
</configuration>
<executions>
<execution>
<id>docker-start</id>
<phase>compile</phase>
<goals>
<goal>stop</goal>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>docker-stop</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -0,0 +1,8 @@
package io.quarkus.it.dynamodb;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/test")
public class DynamoDBApplication extends Application {
}

View File

@@ -0,0 +1,100 @@
package io.quarkus.it.dynamodb;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import java.net.URI;
import java.util.UUID;
import java.util.concurrent.CompletionStage;
import javax.enterprise.event.Observes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import io.quarkus.runtime.StartupEvent;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
@Path("/")
public class DynamoDBResource {
private final static String ASYNC_TABLE = "async";
private final static String BLOCKING_TABLE = "blocking";
private static final Logger LOG = Logger.getLogger(DynamoDBResource.class);
@ConfigProperty(name = "dynamodb.port", defaultValue = "8000")
String dynamoDbPort;
@ConfigProperty(name = "dynamodb.aws", defaultValue = "false")
Boolean useAwsAccount;
private DynamoDbAsyncClient asyncClient;
private DynamoDbClient client;
void onStart(@Observes StartupEvent ev) {
if (useAwsAccount) {
asyncClient = DynamoDbAsyncClient.create();
client = DynamoDbClient.create();
} else {
asyncClient = DynamoDbAsyncClient.builder()
.credentialsProvider(
StaticCredentialsProvider.create(AwsBasicCredentials.create("test-key", "test-secret")))
.region(Region.of("localhost"))
.endpointOverride(URI.create("http://localhost:" + dynamoDbPort))
.build();
client = DynamoDbClient.builder()
.credentialsProvider(
StaticCredentialsProvider.create(AwsBasicCredentials.create("test-key", "test-secret")))
.region(Region.of("localhost"))
.endpointOverride(URI.create("http://localhost:" + dynamoDbPort))
.build();
}
}
@GET
@Path("async")
@Produces(TEXT_PLAIN)
public CompletionStage<String> testAsync() {
LOG.info("Testing Async client with table: " + ASYNC_TABLE);
String keyValue = UUID.randomUUID().toString();
String rangeValue = UUID.randomUUID().toString();
return DynamoDBUtils.createTableIfNotExistsAsync(asyncClient, ASYNC_TABLE)
.thenCompose(t -> asyncClient.putItem(DynamoDBUtils.createPutRequest(ASYNC_TABLE, keyValue, rangeValue, "OK")))
.thenCompose(p -> asyncClient.getItem(DynamoDBUtils.createGetRequest(ASYNC_TABLE, keyValue, rangeValue)))
.thenApply(p -> p.item().get(DynamoDBUtils.PAYLOAD_NAME).s());
}
@GET
@Path("blocking")
@Produces(TEXT_PLAIN)
public String testBlocking() {
LOG.info("Testing Blocking client with table: " + BLOCKING_TABLE);
String keyValue = UUID.randomUUID().toString();
String rangeValue = UUID.randomUUID().toString();
GetItemResponse item = null;
if (DynamoDBUtils.createTableIfNotExists(client, BLOCKING_TABLE)) {
if (client.putItem(DynamoDBUtils.createPutRequest(BLOCKING_TABLE, keyValue, rangeValue, "OK")) != null) {
item = client.getItem(DynamoDBUtils.createGetRequest(BLOCKING_TABLE, keyValue, rangeValue));
}
}
if (item != null) {
return item.item().get(DynamoDBUtils.PAYLOAD_NAME).s();
} else {
return "ERROR";
}
}
}

View File

@@ -0,0 +1,166 @@
package io.quarkus.it.dynamodb;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import org.jboss.logging.Logger;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.model.TableDescription;
import software.amazon.awssdk.services.dynamodb.model.TableStatus;
public class DynamoDBUtils {
private static final Logger LOG = Logger.getLogger(DynamoDBUtils.class);
private final static String KEY_NAME = "keyId";
private final static String RANGE_NAME = "rangeId";
public final static String PAYLOAD_NAME = "payload";
private static final int DEFAULT_WAIT_TIMEOUT = 10 * 60 * 1000; //10 minutes
private static final int DEFAULT_WAIT_INTERVAL = 5 * 1000; //5 seconds
public static boolean createTableIfNotExists(final DynamoDbClient dynamo, final String tableName) {
try {
dynamo.createTable(createTableRequest(tableName));
return waitUntilTableActive(dynamo, tableName);
} catch (ResourceInUseException e) {
LOG.info("Reused existing table");
}
return true;
}
public static CompletableFuture<Boolean> createTableIfNotExistsAsync(final DynamoDbAsyncClient dynamo, String table) {
return dynamo.createTable(DynamoDBUtils.createTableRequest(table))
.thenCompose(resp -> DynamoDBUtils.waitUntilTableActiveAsync(dynamo, table))
.exceptionally(th -> {
if (th.getCause() instanceof ResourceInUseException) {
LOG.info("Reused existing table");
return true;
} else {
LOG.error("Failed table creation", th);
return false;
}
});
}
private static boolean waitUntilTableActive(final DynamoDbClient dynamo, final String tableName) {
long startTime = System.currentTimeMillis();
long endTime = startTime + DEFAULT_WAIT_TIMEOUT;
while (System.currentTimeMillis() < endTime) {
try {
TableDescription table = dynamo.describeTable(DescribeTableRequest.builder().tableName(tableName).build())
.table();
if (table.tableStatus().equals(TableStatus.ACTIVE)) {
return true;
}
} catch (ResourceNotFoundException e) {
// Table doesn't exist yet. Keep pooling
}
try {
Thread.sleep(DEFAULT_WAIT_INTERVAL);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
LOG.info(tableName + " table - Retry table created status");
}
return false;
}
private static CompletableFuture<Boolean> waitUntilTableActiveAsync(final DynamoDbAsyncClient dynamo,
final String table) {
final long startTime = System.currentTimeMillis();
final long endTime = startTime + DEFAULT_WAIT_TIMEOUT;
return retryAsync(() -> dynamo.describeTable(DescribeTableRequest.builder().tableName(table).build()), endTime);
}
private static CompletableFuture<Boolean> retryAsync(Supplier<CompletableFuture<DescribeTableResponse>> action,
final long endTime) {
return action.get()
.thenComposeAsync(result -> {
if (result.table().tableStatus() == TableStatus.ACTIVE) {
return CompletableFuture.completedFuture(true);
} else {
try {
Thread.sleep(DEFAULT_WAIT_INTERVAL);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
LOG.info("Async table - Retry table created status");
if (System.currentTimeMillis() < endTime) {
return retryAsync(action, endTime);
} else {
return CompletableFuture.completedFuture(false);
}
}
});
}
private static CreateTableRequest createTableRequest(String table) {
List<AttributeDefinition> attributeDefinitions = new ArrayList<>();
attributeDefinitions
.add(AttributeDefinition.builder().attributeName(KEY_NAME).attributeType(ScalarAttributeType.S).build());
attributeDefinitions.add(
AttributeDefinition.builder().attributeName(RANGE_NAME).attributeType(ScalarAttributeType.S).build());
List<KeySchemaElement> ks = new ArrayList<>();
ks.add(KeySchemaElement.builder().attributeName(KEY_NAME).keyType(KeyType.HASH).build());
ks.add(KeySchemaElement.builder().attributeName(RANGE_NAME).keyType(KeyType.RANGE).build());
ProvisionedThroughput provisionedthroughput = ProvisionedThroughput.builder().readCapacityUnits(1000L)
.writeCapacityUnits(1000L).build();
return CreateTableRequest.builder()
.tableName(table)
.attributeDefinitions(attributeDefinitions)
.keySchema(ks)
.provisionedThroughput(provisionedthroughput)
.build();
}
public static PutItemRequest createPutRequest(String table, String keyValue, String rangeValue, String payLoad) {
Map<String, AttributeValue> item = new HashMap<>();
item.put(KEY_NAME, AttributeValue.builder().s(keyValue).build());
item.put(RANGE_NAME, AttributeValue.builder().s(rangeValue).build());
item.put(PAYLOAD_NAME, AttributeValue.builder().s(payLoad).build());
return PutItemRequest.builder()
.tableName(table)
.item(item)
.build();
}
public static GetItemRequest createGetRequest(String table, String keyValue, String rangeValue) {
Map<String, AttributeValue> key = new HashMap<>();
key.put(KEY_NAME, AttributeValue.builder().s(keyValue).build());
key.put(RANGE_NAME, AttributeValue.builder().s(rangeValue).build());
return GetItemRequest.builder()
.tableName(table)
.key(key)
.attributesToGet(PAYLOAD_NAME)
.build();
}
}

View File

@@ -0,0 +1,3 @@
quarkus.log.category.\"software.amazon.awssdk\".level=WARN
quarkus.log.category.\"software.amazon.awssdk.request\".level=DEBUG
quarkus.log.category.\"org.apache.http.wire\".level=DEBUG

View File

@@ -0,0 +1,7 @@
package io.quarkus.it.dynamodb;
import io.quarkus.test.junit.SubstrateTest;
@SubstrateTest
public class DynamoDbFunctionalityITCase extends DynamoDbFunctionalityTest {
}

View File

@@ -0,0 +1,27 @@
package io.quarkus.it.dynamodb;
import static org.hamcrest.Matchers.is;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
/**
* Test connecting DynamoDB client to local Dynamodb.
*
*/
@QuarkusTest
public class DynamoDbFunctionalityTest {
@Test
public void testDynamoDbAsync() {
RestAssured.when().get("/test/async").then().body(is("OK"));
}
@Test
public void testDynamoDbBlocking() {
RestAssured.when().get("/test/blocking").then().body(is("OK"));
}
}

View File

@@ -48,6 +48,7 @@
<module>flyway</module>
<module>keycloak</module>
<module>reactive-pg-client</module>
<module>amazon-dynamodb</module>
<module>test-extension</module>
<module>amazon-lambda</module>
<module>kogito</module>