AWS Security ChangesHomeSearch

AWS code-library documentation change

Service: code-library · 2025-03-26 · Documentation low

File: code-library/latest/ug/s3-directory-buckets_example_s3-directory-buckets_Scenario_ExpressBasics_section.md

Summary

Added detailed Java code example demonstrating S3 Express One Zone directory bucket operations including setup, performance comparisons, and structural differences from regular buckets

Security assessment

The changes add example code for working with S3 directory buckets but do not address any specific security vulnerabilities. While the example includes IAM user creation and permissions management, these are standard operational practices rather than security fixes or vulnerability disclosures.

Diff

diff --git a/code-library/latest/ug/s3-directory-buckets_example_s3-directory-buckets_Scenario_ExpressBasics_section.md b/code-library/latest/ug/s3-directory-buckets_example_s3-directory-buckets_Scenario_ExpressBasics_section.md
index 2725443ba..001e870f1 100644
--- a/code-library/latest/ug/s3-directory-buckets_example_s3-directory-buckets_Scenario_ExpressBasics_section.md
+++ b/code-library/latest/ug/s3-directory-buckets_example_s3-directory-buckets_Scenario_ExpressBasics_section.md
@@ -29,0 +30,1109 @@ The following code examples show how to:
+Java
+    
+
+**SDK for Java 2.x**
+    
+
+###### Note
+
+There's more on GitHub. Find the complete example and learn how to set up and run in the [AWS Code Examples Repository](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/s3#code-examples). 
+
+Run an interactive scenario demonstrating Amazon S3 features.
+    
+    
+    public class S3DirectoriesScenario {
+    
+        public static final String DASHES = new String(new char[80]).replace("\0", "-");
+    
+        private static final Logger logger = LoggerFactory.getLogger(S3DirectoriesScenario.class);
+        static Scanner scanner = new Scanner(System.in);
+    
+        private static S3AsyncClient mS3RegularClient;
+        private static S3AsyncClient mS3ExpressClient;
+    
+        private static String mdirectoryBucketName;
+        private static String mregularBucketName;
+    
+        private static String stackName = "cfn-stack-s3-express-basics--" + UUID.randomUUID();
+    
+        private static String regularUser = "";
+        private static String vpcId = "";
+        private static String expressUser = "";
+    
+        private static String vpcEndpointId = "";
+    
+        private static final S3DirectoriesActions s3DirectoriesActions = new S3DirectoriesActions();
+    
+        public static void main(String[] args) {
+            try {
+                s3ExpressScenario();
+            } catch (RuntimeException e) {
+                logger.info(e.getMessage());
+            }
+        }
+    
+        // Runs the scenario.
+        private static void s3ExpressScenario() {
+            logger.info(DASHES);
+            logger.info("Welcome to the Amazon S3 Express Basics demo using AWS SDK for Java V2.");
+            logger.info("""
+                Let's get started! First, please note that S3 Express One Zone works best when working within the AWS infrastructure,
+                specifically when working in the same Availability Zone (AZ). To see the best results in this example and when you implement
+                directory buckets into your infrastructure, it is best to put your compute resources in the same AZ as your directory
+                bucket.
+                """);
+            waitForInputToContinue(scanner);
+            logger.info(DASHES);
+    
+            // Create an optional VPC and create 2 IAM users.
+            UserNames userNames = createVpcUsers();
+            String expressUserName = userNames.getExpressUserName();
+            String regularUserName = userNames.getRegularUserName();
+    
+            //  Set up two S3 clients, one regular and one express,
+            //  and two buckets, one regular and one directory.
+            setupClientsAndBuckets(expressUserName, regularUserName);
+    
+            // Create an S3 session for the express S3 client and add objects to the buckets.
+            logger.info("Now let's add some objects to our buckets and demonstrate how to work with S3 Sessions.");
+            waitForInputToContinue(scanner);
+            String bucketObject = createSessionAddObjects();
+    
+            // Demonstrate performance differences between regular and directory buckets.
+            demonstratePerformance(bucketObject);
+    
+            // Populate the buckets to show the lexicographical difference between
+            // regular and express buckets.
+            showLexicographicalDifferences(bucketObject);
+    
+            logger.info(DASHES);
+            logger.info("That's it for our tour of the basic operations for S3 Express One Zone.");
+            logger.info("Would you like to cleanUp the AWS resources? (y/n): ");
+            String response = scanner.next().trim().toLowerCase();
+            if (response.equals("y")) {
+                cleanUp(stackName);
+            }
+        }
+    
+        /*
+          Delete resources created by this scenario.
+        */
+        public static void cleanUp(String stackName) {
+            try {
+                if (mdirectoryBucketName != null) {
+                    s3DirectoriesActions.deleteBucketAndObjectsAsync(mS3ExpressClient, mdirectoryBucketName).join();
+                }
+                logger.info("Deleted directory bucket " + mdirectoryBucketName);
+                mdirectoryBucketName = null;
+                if (mregularBucketName != null) {
+                    s3DirectoriesActions.deleteBucketAndObjectsAsync(mS3RegularClient, mregularBucketName).join();
+                }
+            } catch (CompletionException ce) {
+                Throwable cause = ce.getCause();
+                if (cause instanceof S3Exception) {
+                    logger.error("S3Exception occurred: {}", cause.getMessage(), ce);
+                } else {
+                    logger.error("An unexpected error occurred: {}", cause.getMessage(), ce);
+                }
+            }
+    
+            logger.info("Deleted regular bucket " + mregularBucketName);
+            mregularBucketName = null;
+            CloudFormationHelper.destroyCloudFormationStack(stackName);
+        }
+    
+        private static void showLexicographicalDifferences(String bucketObject) {
+            logger.info(DASHES);
+            logger.info("""
+                7. Populate the buckets to show the lexicographical (alphabetical) difference 
+                when object names are listed. Now let's explore how directory buckets store 
+                objects in a different manner to regular buckets. The key is in the name 
+                "Directory". Where regular buckets store their key/value pairs in a 
+                flat manner, directory buckets use actual directories/folders. 
+                This allows for more rapid indexing, traversing, and therefore 
+                retrieval times! 
+                            
+                The more segmented your bucket is, with lots of 
+                directories, sub-directories, and objects, the more efficient it becomes. 
+                This structural difference also causes `ListObject` operations to behave 
+                differently, which can cause unexpected results. Let's add a few more 
+                objects in sub-directories to see how the output of 
+                ListObjects changes.
+                """);
+    
+            waitForInputToContinue(scanner);
+    
+            //  Populate a few more files in each bucket so that we can use
+            //  ListObjects and show the difference.
+            String otherObject = "other/" + bucketObject;
+            String altObject = "alt/" + bucketObject;
+            String otherAltObject = "other/alt/" + bucketObject;
+    
+            try {
+                s3DirectoriesActions.putObjectAsync(mS3RegularClient, mregularBucketName, otherObject, "").join();
+                s3DirectoriesActions.putObjectAsync(mS3ExpressClient, mdirectoryBucketName, otherObject, "").join();
+                s3DirectoriesActions.putObjectAsync(mS3RegularClient, mregularBucketName, altObject, "").join();
+                s3DirectoriesActions.putObjectAsync(mS3ExpressClient, mdirectoryBucketName, altObject, "").join();
+                s3DirectoriesActions.putObjectAsync(mS3RegularClient, mregularBucketName, otherAltObject, "").join();
+                s3DirectoriesActions.putObjectAsync(mS3ExpressClient, mdirectoryBucketName, otherAltObject, "").join();
+    
+            } catch (CompletionException ce) {
+                Throwable cause = ce.getCause();
+                if (cause instanceof NoSuchBucketException) {
+                    logger.error("S3Exception occurred: {}", cause.getMessage(), ce);
+                } else {
+                    logger.error("An unexpected error occurred: {}", cause.getMessage(), ce);
+                }
+                return;
+            }
+    
+            try {
+                // List objects in both S3 buckets.
+                List<String> dirBucketObjects = s3DirectoriesActions.listObjectsAsync(mS3ExpressClient, mdirectoryBucketName).join();
+                List<String> regBucketObjects = s3DirectoriesActions.listObjectsAsync(mS3RegularClient, mregularBucketName).join();
+    
+                logger.info("Directory bucket content");
+                for (String obj : dirBucketObjects) {
+                    logger.info(obj);
+                }
+    
+                logger.info("Regular bucket content");
+                for (String obj : regBucketObjects) {
+                    logger.info(obj);
+                }
+            } catch (CompletionException e) {
+                logger.error("Async operation failed: {} ", e.getCause().getMessage());
+                return;
+            }
+    
+            logger.info("""
+                Notice how the regular bucket lists objects in lexicographical order, while the directory bucket does not. This is 
+                because the regular bucket considers the whole "key" to be the object identifier, while the directory bucket actually 
+                creates directories and uses the object "key" as a path to the object.
+                """);
+            waitForInputToContinue(scanner);
+        }
+    
+        /**
+         * Demonstrates the performance difference between downloading an object from a directory bucket and a regular bucket.
+         *
+         * <p>This method:
+         * <ul>
+         *     <li>Prompts the user to choose the number of downloads (default is 1,000).</li>
+         *     <li>Downloads the specified object from the directory bucket and measures the total time.</li>
+         *     <li>Downloads the same object from the regular bucket and measures the total time.</li>
+         *     <li>Compares the time differences and prints the results.</li>