Skip to content

Commit e70a102

Browse files
committed
AWS module
1 parent 2695f29 commit e70a102

File tree

11 files changed

+1846
-14
lines changed

11 files changed

+1846
-14
lines changed

docs/asciidoc/modules.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ configuration properties.
1313

1414
Available modules are listed next.
1515

16+
=== Cloud
17+
* link:modules/aws[AWS]: Amazon Web Service module.
18+
1619
=== Data
1720
* link:modules/flyway[Flyway]: Flyway migration module.
1821
* link:modules/graphql[GraphQL]: GraphQL Java module.

docs/asciidoc/modules/aws.adoc

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
== AmazonWebServices
2+
3+
Amazon Web Services module for https://github.com/aws/aws-sdk-java[aws-sdk-java 1.x]
4+
5+
=== Usage
6+
7+
1) Add the dependency:
8+
9+
[dependency, artifactId="jooby-awssdk-v1"]
10+
.
11+
12+
2) Add required service dependency (S3 here):
13+
14+
[dependency, artifactId="aws-java-sdk-s3"]
15+
.
16+
17+
3) Add the `aws.accessKeyId` and `aws.secretKey` properties:
18+
19+
.application.conf
20+
[source, properties]
21+
----
22+
aws.accessKeyId = "your access key id"
23+
aws.secretKey = "your secret key"
24+
----
25+
26+
This step is optional if you choose one of the https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html[default credentials mechanism].
27+
28+
4) Install
29+
30+
.Java
31+
[source, java, role="primary"]
32+
----
33+
import io.jooby.aws.AwsModule;
34+
35+
{
36+
install(
37+
new AwsModule() <1>
38+
.setup(credentials -> { <2>
39+
return TransferManagerBuilder.standard()
40+
.withS3Client(
41+
AmazonS3ClientBuilder.standard()
42+
.withRegion(Regions.US_EAST_1)
43+
.withCredentials(credentials)
44+
.build() <3>
45+
).build(); <4>
46+
})
47+
);
48+
}
49+
----
50+
51+
.Kotlin
52+
[source, kt, role="secondary"]
53+
----
54+
import io.jooby.aws.AwsModule
55+
56+
{
57+
install(
58+
AwsModule() <1>
59+
.setup { credentials -> <2>
60+
TransferManagerBuilder.standard()
61+
.withS3Client(
62+
AmazonS3ClientBuilder.standard()
63+
.withRegion(Regions.US_EAST_1)
64+
.withCredentials(credentials)
65+
.build() <3>
66+
).build() <4>
67+
})
68+
);
69+
}
70+
----
71+
72+
<1> Install module
73+
<2> Setup one or more services
74+
<3> Creates AmazonS3Client
75+
<3> Creates TransferManager
76+
77+
Services created from setup function are:
78+
79+
- Registered in the application service registry, for require call usage or DI framework
80+
- Services are shutdown at application shutdown time

docs/src/main/java/io/jooby/adoc/DependencyProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class DependencyProcessor extends BlockProcessor {
2727
public DependencyProcessor(String name, Map<String, Object> config) throws IOException {
2828
super(name, config);
2929
pom = Jsoup
30-
.parse(DocGenerator.basedir().getParent().resolve("pom.xml").toFile(), "UTF-8");
30+
.parse(DocGenerator.basedir().getParent().resolve("modules").resolve("jooby-bom").resolve("pom.xml").toFile(), "UTF-8");
3131
}
3232

3333
@Override

modules/jooby-awssdk-v1/pom.xml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
6+
<parent>
7+
<groupId>io.jooby</groupId>
8+
<artifactId>modules</artifactId>
9+
<version>2.5.2-SNAPSHOT</version>
10+
</parent>
11+
12+
<modelVersion>4.0.0</modelVersion>
13+
<artifactId>jooby-awssdk-v1</artifactId>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.google.code.findbugs</groupId>
18+
<artifactId>jsr305</artifactId>
19+
<scope>provided</scope>
20+
</dependency>
21+
22+
<dependency>
23+
<groupId>io.jooby</groupId>
24+
<artifactId>jooby</artifactId>
25+
<version>${jooby.version}</version>
26+
</dependency>
27+
28+
<dependency>
29+
<groupId>com.amazonaws</groupId>
30+
<artifactId>aws-java-sdk-core</artifactId>
31+
</dependency>
32+
33+
<dependency>
34+
<groupId>com.amazonaws</groupId>
35+
<artifactId>aws-java-sdk-s3</artifactId>
36+
<optional>true</optional>
37+
</dependency>
38+
39+
<!-- Test dependencies -->
40+
<dependency>
41+
<groupId>org.junit.jupiter</groupId>
42+
<artifactId>junit-jupiter-engine</artifactId>
43+
<scope>test</scope>
44+
</dependency>
45+
46+
<dependency>
47+
<groupId>org.jacoco</groupId>
48+
<artifactId>org.jacoco.agent</artifactId>
49+
<classifier>runtime</classifier>
50+
<scope>test</scope>
51+
</dependency>
52+
53+
<dependency>
54+
<groupId>io.jooby</groupId>
55+
<artifactId>jooby-test</artifactId>
56+
<scope>test</scope>
57+
</dependency>
58+
</dependencies>
59+
</project>
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/**
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.aws;
7+
8+
import com.amazonaws.auth.AWSCredentialsProvider;
9+
import com.amazonaws.auth.AWSCredentialsProviderChain;
10+
import com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper;
11+
import com.amazonaws.auth.EnvironmentVariableCredentialsProvider;
12+
import com.amazonaws.auth.SystemPropertiesCredentialsProvider;
13+
import com.amazonaws.auth.WebIdentityTokenCredentialsProvider;
14+
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
15+
import com.amazonaws.services.s3.transfer.TransferManager;
16+
import com.typesafe.config.Config;
17+
import io.jooby.Extension;
18+
import io.jooby.Jooby;
19+
import io.jooby.ServiceRegistry;
20+
import io.jooby.internal.aws.ConfigCredentialsProvider;
21+
import io.jooby.internal.aws.ServiceShutdown;
22+
23+
import javax.annotation.Nonnull;
24+
import java.util.ArrayList;
25+
import java.util.Collection;
26+
import java.util.List;
27+
import java.util.Objects;
28+
import java.util.function.Consumer;
29+
import java.util.function.Function;
30+
import java.util.stream.Stream;
31+
32+
/**
33+
* Aws module for aws-java-sdk 1.x. This module:
34+
*
35+
* - Integrates AWS credentials within application properties.
36+
* - Register AWS services as application services (so they can be used by require calls or DI).
37+
* - Add graceful shutdown to AWS services.
38+
*
39+
* Usage:
40+
*
41+
* <pre>{@code
42+
* {
43+
* install(
44+
* new AwsModule()
45+
* .setup(credentials -> {
46+
* return TransferManagerBuilder.standard()
47+
* .withS3Client(
48+
* AmazonS3ClientBuilder.standard()
49+
* .withRegion(Regions.US_EAST_1)
50+
* .withCredentials(credentials)
51+
* .build()
52+
* ).build();
53+
* })
54+
* );
55+
* }
56+
* }</pre>
57+
*
58+
* <p>Previous example register AmazonS3Client and TransferManager services</p>
59+
*
60+
* <p>NOTE: You need to add the required service dependency to your project.</p>
61+
*
62+
* @author edgar
63+
*/
64+
public class AwsModule implements Extension {
65+
66+
private List<Function<AWSCredentialsProvider, Object>> factoryList = new ArrayList<>();
67+
68+
/**
69+
* Setup a new AWS service. Supported outputs are:
70+
*
71+
* - Single amazon service
72+
* - Stream of amazon services
73+
* - Collection of amazon services
74+
*
75+
* Each of the services returned by this function are added to the application service registry
76+
* and shutdown at application shutdown time.
77+
*
78+
* @param provider Service provider/factory.
79+
* @return AWS service.
80+
*/
81+
public @Nonnull AwsModule setup(@Nonnull Function<AWSCredentialsProvider, Object> provider) {
82+
factoryList.add(provider);
83+
return this;
84+
}
85+
86+
@Override public void install(@Nonnull Jooby application) throws Exception {
87+
AWSCredentialsProvider credentialsProvider = newCredentialsProvider(application.getConfig());
88+
List<Object> serviceList = new ArrayList<>(factoryList.size());
89+
for (Function<AWSCredentialsProvider, Object> factory : factoryList) {
90+
Object value = factory.apply(credentialsProvider);
91+
if (value instanceof Stream) {
92+
((Stream) value).forEach(serviceList::add);
93+
} else if (value instanceof Collection) {
94+
((Collection) value).forEach(serviceList::add);
95+
} else {
96+
extractServices(value, serviceList::add);
97+
}
98+
}
99+
ServiceRegistry services = application.getServices();
100+
// for each service
101+
for (Object service : serviceList) {
102+
Stream.of(service.getClass(),
103+
Stream.of(service.getClass().getInterfaces()).findFirst().orElse(null))
104+
.filter(Objects::nonNull)
105+
.forEach(serviceType -> {
106+
services.putIfAbsent((Class) serviceType, service);
107+
});
108+
}
109+
serviceList.stream()
110+
.distinct()
111+
.forEach(service -> application.onStop(new ServiceShutdown(application.getLog(), service)));
112+
serviceList.clear();
113+
factoryList.clear();
114+
}
115+
116+
/**
117+
* Creates a credentials provider, exactly like
118+
* {@link com.amazonaws.auth.DefaultAWSCredentialsProviderChain} appending the application
119+
* properties provider.
120+
*
121+
* @param config Application properties.
122+
* @return Credentials provider.
123+
*/
124+
public static @Nonnull AWSCredentialsProvider newCredentialsProvider(@Nonnull Config config) {
125+
return new AWSCredentialsProviderChain(
126+
new EnvironmentVariableCredentialsProvider(),
127+
new SystemPropertiesCredentialsProvider(),
128+
WebIdentityTokenCredentialsProvider.create(),
129+
new ProfileCredentialsProvider(),
130+
new EC2ContainerCredentialsProviderWrapper(),
131+
// Application configuration
132+
new ConfigCredentialsProvider(config)
133+
);
134+
}
135+
136+
private void extractServices(Object value, Consumer<Object> consumer) {
137+
transferManager(value, consumer);
138+
consumer.accept(value);
139+
}
140+
141+
private void transferManager(Object value, Consumer<Object> consumer) {
142+
try {
143+
if (value instanceof TransferManager) {
144+
consumer.accept(((TransferManager) value).getAmazonS3Client());
145+
}
146+
} catch (NoClassDefFoundError x) {
147+
// s3 dependency is optional
148+
}
149+
}
150+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.internal.aws;
7+
8+
import com.amazonaws.SdkClientException;
9+
import com.amazonaws.auth.AWSCredentials;
10+
import com.amazonaws.auth.AWSCredentialsProvider;
11+
import com.amazonaws.auth.BasicAWSCredentials;
12+
import com.typesafe.config.Config;
13+
import com.typesafe.config.ConfigException;
14+
15+
import static com.amazonaws.SDKGlobalConfiguration.ACCESS_KEY_SYSTEM_PROPERTY;
16+
import static com.amazonaws.SDKGlobalConfiguration.SECRET_KEY_SYSTEM_PROPERTY;
17+
18+
public class ConfigCredentialsProvider implements AWSCredentialsProvider {
19+
20+
private Config config;
21+
22+
public ConfigCredentialsProvider(Config config) {
23+
this.config = config;
24+
}
25+
26+
@Override public AWSCredentials getCredentials() {
27+
try {
28+
return new BasicAWSCredentials(config.getString(ACCESS_KEY_SYSTEM_PROPERTY),
29+
config.getString(SECRET_KEY_SYSTEM_PROPERTY));
30+
} catch (ConfigException.Missing x) {
31+
throw new SdkClientException(
32+
"Unable to load AWS credentials from application properties ("
33+
+ ACCESS_KEY_SYSTEM_PROPERTY + " and " + SECRET_KEY_SYSTEM_PROPERTY + ")");
34+
}
35+
}
36+
37+
@Override public void refresh() {
38+
39+
}
40+
}

0 commit comments

Comments
 (0)