33
33
import software .amazon .awssdk .services .s3 .model .CopyObjectRequest ;
34
34
import software .amazon .awssdk .services .s3 .model .CreateBucketConfiguration ;
35
35
import software .amazon .awssdk .services .s3 .model .CreateBucketRequest ;
36
+ import software .amazon .awssdk .services .s3 .model .CreateBucketResponse ;
36
37
import software .amazon .awssdk .services .s3 .model .CreateSessionRequest ;
38
+ import software .amazon .awssdk .services .s3 .model .CreateSessionResponse ;
37
39
import software .amazon .awssdk .services .s3 .model .DataRedundancy ;
38
40
import software .amazon .awssdk .services .s3 .model .Delete ;
39
41
import software .amazon .awssdk .services .s3 .model .DeleteBucketRequest ;
@@ -116,7 +118,7 @@ private static Ec2AsyncClient getEc2AsyncClient() {
116
118
}
117
119
118
120
/**
119
- * Deletes the specified S3 bucket and all the objects within it in an asynchronous manner .
121
+ * Deletes the specified S3 bucket and all the objects within it asynchronously .
120
122
*
121
123
* @param s3AsyncClient the S3 asynchronous client to use for the operations
122
124
* @param bucketName the name of the S3 bucket to be deleted
@@ -175,10 +177,10 @@ public CompletableFuture<WaiterResponse<HeadBucketResponse>> deleteBucketAndObje
175
177
}
176
178
177
179
/**
178
- * Lists the objects in an S3 bucket asynchronously using the AWS SDK .
180
+ * Lists the objects in an S3 bucket asynchronously.
179
181
*
180
- * @param s3Client the S3 async client to use for the operation
181
- * @param bucketName the name of the S3 bucket to list objects from
182
+ * @param s3Client the S3 async client to use for the operation
183
+ * @param bucketName the name of the the S3 bucket containing the objects to list
182
184
* @return a {@link CompletableFuture} that contains the list of object keys in the specified bucket
183
185
*/
184
186
public CompletableFuture <List <String >> listObjectsAsync (S3AsyncClient s3Client , String bucketName ) {
@@ -197,6 +199,14 @@ public CompletableFuture<List<String>> listObjectsAsync(S3AsyncClient s3Client,
197
199
});
198
200
}
199
201
202
+ /**
203
+ * Retrieves an object from an Amazon S3 bucket asynchronously.
204
+ *
205
+ * @param s3Client the S3 async client to use for the operation
206
+ * @param bucketName the name of the S3 bucket containing the object
207
+ * @param keyName the unique identifier (key) of the object to retrieve
208
+ * @return a {@link CompletableFuture} that, when completed, contains the object's content as a {@link ResponseBytes} of {@link GetObjectResponse}
209
+ */
200
210
public CompletableFuture <ResponseBytes <GetObjectResponse >> getObjectAsync (S3AsyncClient s3Client , String bucketName , String keyName ) {
201
211
GetObjectRequest objectRequest = GetObjectRequest .builder ()
202
212
.key (keyName )
@@ -206,7 +216,6 @@ public CompletableFuture<ResponseBytes<GetObjectResponse>> getObjectAsync(S3Asyn
206
216
// Get the object asynchronously and transform it into a byte array
207
217
return s3Client .getObject (objectRequest , AsyncResponseTransformer .toBytes ())
208
218
.exceptionally (exception -> {
209
- // Handle the exception by checking the cause
210
219
Throwable cause = exception .getCause ();
211
220
if (cause instanceof S3Exception ) {
212
221
throw new CompletionException ("Failed to get the object. Reason: " + ((S3Exception ) cause ).awsErrorDetails ().errorMessage (), cause );
@@ -218,6 +227,7 @@ public CompletableFuture<ResponseBytes<GetObjectResponse>> getObjectAsync(S3Asyn
218
227
return response ;
219
228
});
220
229
}
230
+
221
231
/**
222
232
* Asynchronously copies an object from one S3 bucket to another.
223
233
*
@@ -250,40 +260,41 @@ public CompletableFuture<Void> copyObjectAsync(S3AsyncClient s3Client, String so
250
260
}
251
261
252
262
/**
253
- * Creates an asynchronous session for the specified S3 bucket.
263
+ * Asynchronously creates a session for the specified S3 bucket.
254
264
*
255
- * @param s3Client the S3 asynchronous client to use for creating the session
265
+ * @param s3Client the S3 asynchronous client to use for creating the session
256
266
* @param bucketName the name of the S3 bucket for which to create the session
257
267
* @return a {@link CompletableFuture} that completes when the session is created, or throws a {@link CompletionException} if an error occurs
258
268
*/
259
- public CompletableFuture <Void > createSessionAsync (S3AsyncClient s3Client , String bucketName ) {
269
+ public CompletableFuture <CreateSessionResponse > createSessionAsync (S3AsyncClient s3Client , String bucketName ) {
260
270
CreateSessionRequest request = CreateSessionRequest .builder ()
261
271
.bucket (bucketName )
262
272
.build ();
263
273
264
274
return s3Client .createSession (request )
265
- .thenRun (() -> logger .info ("Created session for bucket: " + bucketName ))
266
- .whenComplete ((ignored , exception ) -> {
275
+ .whenComplete ((response , exception ) -> {
267
276
if (exception != null ) {
268
277
Throwable cause = exception .getCause ();
269
278
if (cause instanceof S3Exception ) {
270
279
throw new CompletionException ("Couldn't create the session. Reason: " + ((S3Exception ) cause ).awsErrorDetails ().errorMessage (), cause );
271
280
}
272
281
throw new CompletionException ("Unexpected error occurred while creating session" , exception );
273
282
}
283
+ logger .info ("Created session for bucket: " + bucketName );
274
284
});
285
+
275
286
}
276
287
277
288
/**
278
289
* Creates a new S3 directory bucket in a specified Zone (For example, a
279
290
* specified Availability Zone in this code example).
280
291
*
281
- * @param s3Client The S3 client used to create the bucket
292
+ * @param s3Client The asynchronous S3 client used to create the bucket
282
293
* @param bucketName The name of the bucket to be created
283
- * @param zone The region where the bucket will be created
284
- * @throws S3Exception if there's an error creating the bucket
294
+ * @param zone The Availability Zone where the bucket will be created
295
+ * @throws CompletionException if there's an error creating the bucket
285
296
*/
286
- public CompletableFuture <Void > createDirectoryBucketAsync (S3AsyncClient s3Client , String bucketName , String zone ) {
297
+ public CompletableFuture <CreateBucketResponse > createDirectoryBucketAsync (S3AsyncClient s3Client , String bucketName , String zone ) {
287
298
logger .info ("Creating bucket: " + bucketName );
288
299
289
300
CreateBucketConfiguration bucketConfiguration = CreateBucketConfiguration .builder ()
@@ -303,17 +314,18 @@ public CompletableFuture<Void> createDirectoryBucketAsync(S3AsyncClient s3Client
303
314
.build ();
304
315
305
316
return s3Client .createBucket (bucketRequest )
306
- .thenAccept (response -> logger .info ("Bucket created successfully with location: " + response .location ()))
307
- .whenComplete ((ignored , exception ) -> {
317
+ .whenComplete ((response , exception ) -> {
308
318
if (exception != null ) {
309
319
Throwable cause = exception .getCause ();
310
320
if (cause instanceof S3Exception ) {
311
321
throw new CompletionException ("Error creating bucket: " + ((S3Exception ) cause ).awsErrorDetails ().errorMessage (), cause );
312
322
}
313
323
throw new CompletionException ("Unexpected error occurred while creating bucket" , exception );
314
324
}
325
+ logger .info ("Bucket created successfully with location: " + response .location ());
315
326
});
316
327
}
328
+
317
329
/**
318
330
* Creates an S3 bucket asynchronously.
319
331
*
@@ -348,7 +360,7 @@ public CompletableFuture<WaiterResponse<HeadBucketResponse>> createBucketAsync(S
348
360
* Uploads an object to an Amazon S3 bucket asynchronously.
349
361
*
350
362
* @param s3Client the S3 async client to use for the upload
351
- * @param bucketName the name of the S3 bucket to upload the object to
363
+ * @param bucketName the destination S3 bucket name
352
364
* @param bucketObject the name of the object to be uploaded
353
365
* @param text the content to be uploaded as the object
354
366
*/
@@ -397,12 +409,12 @@ public CompletableFuture<CreateAccessKeyResponse> createAccessKeyAsync(String us
397
409
}
398
410
399
411
/**
400
- * Selects an availability zone ID based on the specified AWS region .
412
+ * Asynchronously selects an Availability Zone ID from the available EC2 zones .
401
413
*
402
- * @return A map containing the selected availability zone details, including the zone name, zone ID, region name, and state.
414
+ * @return A {@link CompletableFuture} that resolves to the selected Availability Zone ID.
415
+ * @throws CompletionException if an error occurs during the request or processing.
403
416
*/
404
417
public CompletableFuture <String > selectAvailabilityZoneIdAsync () {
405
- // Request available zones
406
418
DescribeAvailabilityZonesRequest zonesRequest = DescribeAvailabilityZonesRequest .builder ()
407
419
.build ();
408
420
@@ -415,15 +427,13 @@ public CompletableFuture<String> selectAvailabilityZoneIdAsync() {
415
427
return CompletableFuture .completedFuture (null ); // Return null if no zones are found
416
428
}
417
429
418
- // Extract zone IDs
419
430
List <String > zoneIds = zonesList .stream ()
420
431
.map (AvailabilityZone ::zoneId ) // Get the zoneId (e.g., "usw2-az1")
421
432
.toList ();
422
433
423
- // **Prompt user synchronously** and return CompletableFuture
424
434
return CompletableFuture .supplyAsync (() -> promptUserForZoneSelection (zonesList , zoneIds ))
425
435
.thenApply (selectedZone -> {
426
- // Return only the selected Zone ID (e.g., "usw2-az1")
436
+ // Return only the selected Zone ID (e.g., "usw2-az1").
427
437
return selectedZone .zoneId ();
428
438
});
429
439
})
@@ -445,7 +455,7 @@ public CompletableFuture<String> selectAvailabilityZoneIdAsync() {
445
455
}
446
456
447
457
/**
448
- * Prompts the user to select an availability zone from the given list.
458
+ * Prompts the user to select an Availability Zone from the given list.
449
459
*
450
460
* @param zonesList the list of availability zones
451
461
* @param zoneIds the list of zone IDs
@@ -458,21 +468,30 @@ private static AvailabilityZone promptUserForZoneSelection(List<AvailabilityZone
458
468
while (index < 0 || index >= zoneIds .size ()) {
459
469
logger .info ("Select an availability zone:" );
460
470
IntStream .range (0 , zoneIds .size ()).forEach (i ->
461
- System . out . println (i + ": " + zoneIds .get (i )) // Display Zone IDs
471
+ logger . info (i + ": " + zoneIds .get (i ))
462
472
);
463
473
464
474
logger .info ("Enter the number corresponding to your choice: " );
465
475
if (scanner .hasNextInt ()) {
466
476
index = scanner .nextInt ();
467
477
} else {
468
- scanner .next (); // Consume invalid input
478
+ scanner .next ();
469
479
}
470
480
}
471
481
472
482
AvailabilityZone selectedZone = zonesList .get (index );
473
- logger .info ("You selected: " + selectedZone .zoneId ()); // Log Zone ID
483
+ logger .info ("You selected: " + selectedZone .zoneId ());
474
484
return selectedZone ;
475
485
}
486
+
487
+ /**
488
+ * Asynchronously sets up an AWS VPC, including creating a VPC, waiting for it to be available,
489
+ * retrieving its associated route table, and creating a VPC endpoint for S3 Express.
490
+ *
491
+ * @return A {@link CompletableFuture} that completes when the VPC setup is finished.
492
+ * If an error occurs, a {@link CompletionException} is thrown.
493
+ * @throws CompletionException if an EC2-related error occurs or if required resources are missing.
494
+ */
476
495
public CompletableFuture <Void > setupVPCAsync () {
477
496
String cidr = "10.0.0.0/16" ;
478
497
CreateVpcRequest vpcRequest = CreateVpcRequest .builder ()
@@ -483,7 +502,6 @@ public CompletableFuture<Void> setupVPCAsync() {
483
502
.thenCompose (vpcResponse -> {
484
503
String vpcId = vpcResponse .vpc ().vpcId ();
485
504
486
- // Wait for VPC to be available
487
505
Ec2AsyncWaiter waiter = ec2AsyncClient .waiter ();
488
506
DescribeVpcsRequest request = DescribeVpcsRequest .builder ()
489
507
.vpcIds (vpcId )
@@ -493,7 +511,6 @@ public CompletableFuture<Void> setupVPCAsync() {
493
511
.thenApply (waiterResponse -> vpcId );
494
512
})
495
513
.thenCompose (vpcId -> {
496
- // Fetch route table for VPC
497
514
Filter filter = Filter .builder ()
498
515
.name ("vpc-id" )
499
516
.values (vpcId )
@@ -546,6 +563,6 @@ public CompletableFuture<Void> setupVPCAsync() {
546
563
throw new CompletionException ("VPC setup failed: " + exception .getMessage (), exception );
547
564
}
548
565
})
549
- .thenAccept (v -> {}); // Ensure CompletableFuture<Void> return type
566
+ .thenAccept (v -> {});
550
567
}
551
568
}
0 commit comments