Skip to content

Commit 2041521

Browse files
committed
addressed additional comments
1 parent 42c963b commit 2041521

File tree

3 files changed

+306
-89
lines changed

3 files changed

+306
-89
lines changed

javav2/example_code/s3/src/main/java/com/example/s3/express/S3DirectoriesActions.java

Lines changed: 52 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import software.amazon.awssdk.services.iam.model.CreateAccessKeyResponse;
2929
import software.amazon.awssdk.services.iam.model.IamException;
3030
import software.amazon.awssdk.services.s3.S3AsyncClient;
31+
import software.amazon.awssdk.services.s3.model.BucketAlreadyExistsException;
3132
import software.amazon.awssdk.services.s3.model.BucketInfo;
3233
import software.amazon.awssdk.services.s3.model.BucketType;
3334
import software.amazon.awssdk.services.s3.model.CopyObjectRequest;
@@ -47,6 +48,8 @@
4748
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
4849
import software.amazon.awssdk.services.s3.model.LocationInfo;
4950
import software.amazon.awssdk.services.s3.model.LocationType;
51+
import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
52+
import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
5053
import software.amazon.awssdk.services.s3.model.ObjectIdentifier;
5154
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
5255
import software.amazon.awssdk.services.s3.model.S3Object;
@@ -181,7 +184,7 @@ public CompletableFuture<WaiterResponse<HeadBucketResponse>> deleteBucketAndObje
181184
* Lists the objects in an S3 bucket asynchronously.
182185
*
183186
* @param s3Client the S3 async client to use for the operation
184-
* @param bucketName the name of the the S3 bucket containing the objects to list
187+
* @param bucketName the name of the S3 bucket containing the objects to list
185188
* @return a {@link CompletableFuture} that contains the list of object keys in the specified bucket
186189
*/
187190
public CompletableFuture<List<String>> listObjectsAsync(S3AsyncClient s3Client, String bucketName) {
@@ -218,14 +221,10 @@ public CompletableFuture<ResponseBytes<GetObjectResponse>> getObjectAsync(S3Asyn
218221
return s3Client.getObject(objectRequest, AsyncResponseTransformer.toBytes())
219222
.exceptionally(exception -> {
220223
Throwable cause = exception.getCause();
221-
if (cause instanceof S3Exception) {
224+
if (cause instanceof NoSuchKeyException) {
222225
throw new CompletionException("Failed to get the object. Reason: " + ((S3Exception) cause).awsErrorDetails().errorMessage(), cause);
223226
}
224227
throw new CompletionException("Failed to get the object", exception);
225-
})
226-
.thenApply(response -> {
227-
logger.info("Successfully obtained bytes from an S3 object");
228-
return response;
229228
});
230229
}
231230

@@ -318,8 +317,8 @@ public CompletableFuture<CreateBucketResponse> createDirectoryBucketAsync(S3Asyn
318317
.whenComplete((response, exception) -> {
319318
if (exception != null) {
320319
Throwable cause = exception.getCause();
321-
if (cause instanceof S3Exception) {
322-
throw new CompletionException("Error creating bucket: " + ((S3Exception) cause).awsErrorDetails().errorMessage(), cause);
320+
if (cause instanceof BucketAlreadyExistsException) {
321+
throw new CompletionException("The bucket already exists: " + ((S3Exception) cause).awsErrorDetails().errorMessage(), cause);
323322
}
324323
throw new CompletionException("Unexpected error occurred while creating bucket", exception);
325324
}
@@ -351,7 +350,12 @@ public CompletableFuture<WaiterResponse<HeadBucketResponse>> createBucketAsync(S
351350
})
352351
.whenComplete((response, exception) -> {
353352
if (exception != null) {
354-
throw new CompletionException("Error creating bucket: " + bucketName, exception);
353+
Throwable cause = exception.getCause();
354+
if (cause instanceof BucketAlreadyExistsException) {
355+
throw new CompletionException("The S3 bucket exists: " + cause.getMessage(), cause);
356+
} else {
357+
throw new CompletionException("Failed to create access key: " + exception.getMessage(), exception);
358+
}
355359
}
356360
logger.info(bucketName + " is ready");
357361
});
@@ -374,7 +378,12 @@ public CompletableFuture<PutObjectResponse> putObjectAsync(S3AsyncClient s3Clien
374378
return s3Client.putObject(objectRequest, AsyncRequestBody.fromString(text))
375379
.whenComplete((response, exception) -> {
376380
if (exception != null) {
377-
throw new CompletionException("Failed to upload file", exception);
381+
Throwable cause = exception.getCause();
382+
if (cause instanceof NoSuchBucketException) {
383+
throw new CompletionException("The S3 bucket does not exist: " + cause.getMessage(), cause);
384+
} else {
385+
throw new CompletionException("Failed to create access key: " + exception.getMessage(), exception);
386+
}
378387
}
379388
});
380389
}
@@ -396,15 +405,13 @@ public CompletableFuture<CreateAccessKeyResponse> createAccessKeyAsync(String us
396405
logger.info("Access Key Created.");
397406
} else {
398407
if (exception == null) {
399-
throw new CompletionException("An unknown error occurred while creating access key.", null);
400-
}
401-
402-
Throwable cause = exception.getCause();
403-
if (cause instanceof IamException) {
404-
throw new CompletionException("IAM error while creating access key: " + cause.getMessage(), cause);
408+
Throwable cause = exception.getCause();
409+
if (cause instanceof IamException) {
410+
throw new CompletionException("IAM error while creating access key: " + cause.getMessage(), cause);
411+
} else {
412+
throw new CompletionException("Failed to create access key: " + exception.getMessage(), exception);
413+
}
405414
}
406-
407-
throw new CompletionException("Failed to create access key: " + exception.getMessage(), exception);
408415
}
409416
});
410417
}
@@ -422,7 +429,6 @@ public CompletableFuture<String> selectAvailabilityZoneIdAsync() {
422429
return getEc2AsyncClient().describeAvailabilityZones(zonesRequest)
423430
.thenCompose(response -> {
424431
List<AvailabilityZone> zonesList = response.availabilityZones();
425-
426432
if (zonesList.isEmpty()) {
427433
logger.info("No availability zones found.");
428434
return CompletableFuture.completedFuture(null); // Return null if no zones are found
@@ -458,9 +464,9 @@ public CompletableFuture<String> selectAvailabilityZoneIdAsync() {
458464
/**
459465
* Prompts the user to select an Availability Zone from the given list.
460466
*
461-
* @param zonesList the list of availability zones
467+
* @param zonesList the list of Availability Zones
462468
* @param zoneIds the list of zone IDs
463-
* @return the selected AvailabilityZone
469+
* @return the selected Availability Zone
464470
*/
465471
private static AvailabilityZone promptUserForZoneSelection(List<AvailabilityZone> zonesList, List<String> zoneIds) {
466472
Scanner scanner = new Scanner(System.in);
@@ -486,14 +492,13 @@ private static AvailabilityZone promptUserForZoneSelection(List<AvailabilityZone
486492
}
487493

488494
/**
489-
* Asynchronously sets up an AWS VPC, including creating a VPC, waiting for it to be available,
490-
* retrieving its associated route table, and creating a VPC endpoint for S3 Express.
495+
* Asynchronously sets up a new VPC, including creating the VPC, finding the associated route table, and
496+
* creating a VPC endpoint for the S3 service.
491497
*
492-
* @return A {@link CompletableFuture} that completes when the VPC setup is finished.
493-
* If an error occurs, a {@link CompletionException} is thrown.
494-
* @throws CompletionException if an EC2-related error occurs or if required resources are missing.
498+
* @return a {@link CompletableFuture} that, when completed, contains a AbstractMap with the
499+
* VPC ID and VPC endpoint ID.
495500
*/
496-
public CompletableFuture<Void> setupVPCAsync() {
501+
public CompletableFuture<AbstractMap.SimpleEntry<String, String>> setupVPCAsync() {
497502
String cidr = "10.0.0.0/16";
498503
CreateVpcRequest vpcRequest = CreateVpcRequest.builder()
499504
.cidrBlock(cidr)
@@ -502,8 +507,9 @@ public CompletableFuture<Void> setupVPCAsync() {
502507
return getEc2AsyncClient().createVpc(vpcRequest)
503508
.thenCompose(vpcResponse -> {
504509
String vpcId = vpcResponse.vpc().vpcId();
510+
logger.info("VPC Created: {}", vpcId);
505511

506-
Ec2AsyncWaiter waiter = ec2AsyncClient.waiter();
512+
Ec2AsyncWaiter waiter = getEc2AsyncClient().waiter();
507513
DescribeVpcsRequest request = DescribeVpcsRequest.builder()
508514
.vpcIds(vpcId)
509515
.build();
@@ -521,18 +527,20 @@ public CompletableFuture<Void> setupVPCAsync() {
521527
.filters(filter)
522528
.build();
523529

524-
return ec2AsyncClient.describeRouteTables(describeRouteTablesRequest)
530+
return getEc2AsyncClient().describeRouteTables(describeRouteTablesRequest)
525531
.thenApply(routeTablesResponse -> {
526532
if (routeTablesResponse.routeTables().isEmpty()) {
527-
throw new CompletionException("No route tables found for VPC.", null);
533+
throw new CompletionException("No route tables found for VPC: " + vpcId, null);
528534
}
529-
return new AbstractMap.SimpleEntry<>(vpcId, routeTablesResponse.routeTables().get(0).routeTableId());
535+
String routeTableId = routeTablesResponse.routeTables().get(0).routeTableId();
536+
logger.info("Route table found: {}", routeTableId);
537+
return new AbstractMap.SimpleEntry<>(vpcId, routeTableId);
530538
});
531539
})
532540
.thenCompose(vpcAndRouteTable -> {
533541
String vpcId = vpcAndRouteTable.getKey();
534542
String routeTableId = vpcAndRouteTable.getValue();
535-
Region region = ec2AsyncClient.serviceClientConfiguration().region();
543+
Region region = getEc2AsyncClient().serviceClientConfiguration().region();
536544
String serviceName = String.format("com.amazonaws.%s.s3express", region.id());
537545

538546
CreateVpcEndpointRequest endpointRequest = CreateVpcEndpointRequest.builder()
@@ -541,30 +549,24 @@ public CompletableFuture<Void> setupVPCAsync() {
541549
.serviceName(serviceName)
542550
.build();
543551

544-
return ec2AsyncClient.createVpcEndpoint(endpointRequest)
552+
return getEc2AsyncClient().createVpcEndpoint(endpointRequest)
545553
.thenApply(vpcEndpointResponse -> {
546554
String vpcEndpointId = vpcEndpointResponse.vpcEndpoint().vpcEndpointId();
555+
logger.info("VPC Endpoint created: {}", vpcEndpointId);
547556
return new AbstractMap.SimpleEntry<>(vpcId, vpcEndpointId);
548557
});
549558
})
550-
.whenComplete((result, exception) -> {
551-
if (result != null) {
552-
logger.info("Created VPC: {}", result.getKey());
553-
logger.info("Created VPC Endpoint: {}", result.getValue());
554-
} else {
555-
if (exception == null) {
556-
throw new CompletionException("An unknown error occurred during VPC setup.", null);
557-
}
558-
559-
Throwable cause = exception.getCause();
560-
if (cause instanceof Ec2Exception) {
561-
throw new CompletionException("EC2 error during VPC setup: " + cause.getMessage(), cause);
562-
}
563-
564-
throw new CompletionException("VPC setup failed: " + exception.getMessage(), exception);
559+
.exceptionally(exception -> {
560+
Throwable cause = exception.getCause() != null ? exception.getCause() : exception;
561+
if (cause instanceof Ec2Exception) {
562+
logger.error("EC2 error during VPC setup: {}", cause.getMessage(), cause);
563+
throw new CompletionException("EC2 error during VPC setup: " + cause.getMessage(), cause);
565564
}
566-
})
567-
.thenAccept(v -> {});
565+
566+
logger.error("VPC setup failed: {}", cause.getMessage(), cause);
567+
throw new CompletionException("VPC setup failed: " + cause.getMessage(), cause);
568+
});
568569
}
570+
569571
}
570572
// snippet-end:[s3.java2.directories.actions.main]

0 commit comments

Comments
 (0)