Skip to content

Commit e2713b2

Browse files
authored
Java v2 Add S3 Express Scenario (awsdocs#7270)
* JavaV2: S3 Express Scenario
1 parent 5fb4033 commit e2713b2

File tree

10 files changed

+1610
-5
lines changed

10 files changed

+1610
-5
lines changed

.doc_gen/metadata/s3-directory-buckets_metadata.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,18 @@ s3-directory-buckets_Scenario_ExpressBasics:
418418
- Prompt the user to see if they want to clean up the resources.
419419
category: Basics
420420
languages:
421+
Java:
422+
versions:
423+
- sdk_version: 2
424+
github: javav2/example_code/s3
425+
sdkguide:
426+
excerpts:
427+
- description: Run an interactive scenario demonstrating &S3; features.
428+
snippet_tags:
429+
- s3.java2.directories.scenario.main
430+
- description: A wrapper class for &S3; SDK methods.
431+
snippet_tags:
432+
- s3.java2.directories.actions.main
421433
PHP:
422434
versions:
423435
- sdk_version: 3

javav2/example_code/s3/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@
157157
<groupId>software.amazon.awssdk</groupId>
158158
<artifactId>iam</artifactId>
159159
</dependency>
160+
<dependency>
161+
<groupId>software.amazon.awssdk</groupId>
162+
<artifactId>ec2</artifactId>
163+
</dependency>
160164
<dependency>
161165
<groupId>org.apache.logging.log4j</groupId>
162166
<artifactId>log4j-core</artifactId>

javav2/example_code/s3/src/main/java/com/example/s3/directorybucket/DeleteDirectoryBucketObjects.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,23 +69,20 @@ public static void deleteDirectoryBucketObjects(S3Client s3Client, String bucket
6969
logger.info("Deleting objects from bucket: {}", bucketName);
7070

7171
try {
72-
// Create a list of ObjectIdentifier
72+
// Create a list of ObjectIdentifier.
7373
List<ObjectIdentifier> identifiers = objectKeys.stream()
7474
.map(key -> ObjectIdentifier.builder().key(key).build())
7575
.toList();
7676

77-
// Create a Delete object
7877
Delete delete = Delete.builder()
7978
.objects(identifiers)
8079
.build();
8180

82-
// Create a DeleteObjectsRequest
8381
DeleteObjectsRequest deleteObjectsRequest = DeleteObjectsRequest.builder()
8482
.bucket(bucketName)
8583
.delete(delete)
8684
.build();
8785

88-
// Delete the objects
8986
DeleteObjectsResponse deleteObjectsResponse = s3Client.deleteObjects(deleteObjectsRequest);
9087
deleteObjectsResponse.deleted().forEach(deleted -> logger.info("Deleted object: {}", deleted.key()));
9188

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package com.example.s3.express;
5+
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
9+
import software.amazon.awssdk.core.retry.RetryMode;
10+
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
11+
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
12+
import software.amazon.awssdk.services.cloudformation.CloudFormationAsyncClient;
13+
import software.amazon.awssdk.services.cloudformation.model.Capability;
14+
import software.amazon.awssdk.services.cloudformation.model.CloudFormationException;
15+
import software.amazon.awssdk.services.cloudformation.model.DescribeStacksRequest;
16+
import software.amazon.awssdk.services.cloudformation.model.DescribeStacksResponse;
17+
import software.amazon.awssdk.services.cloudformation.model.Output;
18+
import software.amazon.awssdk.services.cloudformation.model.Stack;
19+
import software.amazon.awssdk.services.cloudformation.waiters.CloudFormationAsyncWaiter;
20+
21+
import java.io.IOException;
22+
import java.net.URISyntaxException;
23+
import java.nio.file.Files;
24+
import java.nio.file.Path;
25+
import java.nio.file.Paths;
26+
import java.time.Duration;
27+
import java.util.HashMap;
28+
import java.util.List;
29+
import java.util.Map;
30+
import java.util.concurrent.CompletableFuture;
31+
32+
public class CloudFormationHelper {
33+
private static final String CFN_TEMPLATE = "s3_express_template.yaml";
34+
private static final Logger logger = LoggerFactory.getLogger(CloudFormationHelper.class);
35+
36+
private static CloudFormationAsyncClient cloudFormationClient;
37+
38+
private static CloudFormationAsyncClient getCloudFormationClient() {
39+
if (cloudFormationClient == null) {
40+
SdkAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder()
41+
.maxConcurrency(100)
42+
.connectionTimeout(Duration.ofSeconds(60))
43+
.readTimeout(Duration.ofSeconds(60))
44+
.writeTimeout(Duration.ofSeconds(60))
45+
.build();
46+
47+
ClientOverrideConfiguration overrideConfig = ClientOverrideConfiguration.builder()
48+
.apiCallTimeout(Duration.ofMinutes(2))
49+
.apiCallAttemptTimeout(Duration.ofSeconds(90))
50+
.retryStrategy(RetryMode.STANDARD)
51+
.build();
52+
53+
cloudFormationClient = CloudFormationAsyncClient.builder()
54+
.httpClient(httpClient)
55+
.overrideConfiguration(overrideConfig)
56+
.build();
57+
}
58+
return cloudFormationClient;
59+
}
60+
61+
public static void deployCloudFormationStack(String stackName) {
62+
String templateBody;
63+
boolean doesExist = describeStack(stackName);
64+
if (!doesExist) {
65+
try {
66+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
67+
Path filePath = Paths.get(classLoader.getResource(CFN_TEMPLATE).toURI());
68+
templateBody = Files.readString(filePath);
69+
} catch (IOException | URISyntaxException e) {
70+
throw new RuntimeException(e);
71+
}
72+
73+
getCloudFormationClient().createStack(b -> b.stackName(stackName)
74+
.templateBody(templateBody)
75+
.capabilities(Capability.CAPABILITY_IAM))
76+
.whenComplete((csr, t) -> {
77+
if (csr != null) {
78+
System.out.println("Stack creation requested, ARN is " + csr.stackId());
79+
try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
80+
waiter.waitUntilStackCreateComplete(request -> request.stackName(stackName))
81+
.whenComplete((dsr, th) -> {
82+
if (th != null) {
83+
System.out.println("Error waiting for stack creation: " + th.getMessage());
84+
} else {
85+
dsr.matched().response().orElseThrow(() -> new RuntimeException("Failed to deploy"));
86+
System.out.println("Stack created successfully");
87+
}
88+
}).join();
89+
}
90+
} else {
91+
System.out.format("Error creating stack: " + t.getMessage(), t);
92+
throw new RuntimeException(t.getCause().getMessage(), t);
93+
}
94+
}).join();
95+
} else {
96+
logger.info("{} stack already exists", CFN_TEMPLATE);
97+
}
98+
}
99+
100+
// Check to see if the Stack exists before deploying it
101+
public static Boolean describeStack(String stackName) {
102+
try {
103+
CompletableFuture<?> future = getCloudFormationClient().describeStacks();
104+
DescribeStacksResponse stacksResponse = (DescribeStacksResponse) future.join();
105+
List<Stack> stacks = stacksResponse.stacks();
106+
for (Stack myStack : stacks) {
107+
if (myStack.stackName().compareTo(stackName) == 0) {
108+
return true;
109+
}
110+
}
111+
} catch (CloudFormationException e) {
112+
System.err.println(e.getMessage());
113+
}
114+
return false;
115+
}
116+
117+
public static void destroyCloudFormationStack(String stackName) {
118+
getCloudFormationClient().deleteStack(b -> b.stackName(stackName))
119+
.whenComplete((dsr, t) -> {
120+
if (dsr != null) {
121+
System.out.println("Delete stack requested ....");
122+
try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
123+
waiter.waitUntilStackDeleteComplete(request -> request.stackName(stackName))
124+
.whenComplete((waiterResponse, throwable) ->
125+
System.out.println("Stack deleted successfully."))
126+
.join();
127+
}
128+
} else {
129+
System.out.format("Error deleting stack: " + t.getMessage(), t);
130+
throw new RuntimeException(t.getCause().getMessage(), t);
131+
}
132+
}).join();
133+
}
134+
135+
public static CompletableFuture<Map<String, String>> getStackOutputsAsync(String stackName) {
136+
CloudFormationAsyncClient cloudFormationAsyncClient = getCloudFormationClient();
137+
138+
DescribeStacksRequest describeStacksRequest = DescribeStacksRequest.builder()
139+
.stackName(stackName)
140+
.build();
141+
142+
return cloudFormationAsyncClient.describeStacks(describeStacksRequest)
143+
.handle((describeStacksResponse, throwable) -> {
144+
if (throwable != null) {
145+
throw new RuntimeException("Failed to get stack outputs for: " + stackName, throwable);
146+
}
147+
148+
// Process the result
149+
if (describeStacksResponse.stacks().isEmpty()) {
150+
throw new RuntimeException("Stack not found: " + stackName);
151+
}
152+
153+
Stack stack = describeStacksResponse.stacks().get(0);
154+
Map<String, String> outputs = new HashMap<>();
155+
for (Output output : stack.outputs()) {
156+
outputs.put(output.outputKey(), output.outputValue());
157+
}
158+
159+
return outputs;
160+
});
161+
}
162+
}

0 commit comments

Comments
 (0)