diff --git a/.doc_gen/metadata/s3_metadata.yaml b/.doc_gen/metadata/s3_metadata.yaml
index 3a298d854f1..820cbc490a0 100644
--- a/.doc_gen/metadata/s3_metadata.yaml
+++ b/.doc_gen/metadata/s3_metadata.yaml
@@ -3524,3 +3524,20 @@ s3_Scenario_DownloadS3Directory:
- s3.tm.java2.download-s3-directories.main
services:
s3: {}
+s3_Scenario_DoesBucketExist:
+ title: Check if a bucket exists
+ title_abbrev: Check if a bucket exists
+ synopsis: check if a bucket exists.
+ category: Scenarios
+ languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/s3
+ sdkguide:
+ excerpts:
+ - description: You can use the following doesBucketExists method as a replacement for the the &Java; V1 AmazonS3Client#doesBucketExistV2(String) method.
+ snippet_tags:
+ - s3.java2.does-bucket-exist-main
+ services:
+ s3: {GetBucketAcl}
diff --git a/javav2/example_code/s3/README.md b/javav2/example_code/s3/README.md
index 2cb2d77f762..39d43368f83 100644
--- a/javav2/example_code/s3/README.md
+++ b/javav2/example_code/s3/README.md
@@ -79,6 +79,7 @@ Code excerpts that show you how to call individual service functions.
Code examples that show you how to accomplish a specific task by calling multiple
functions within the same service.
+- [Check if a bucket exists](src/main/java/com/example/s3/DoesBucketExist.java)
- [Delete incomplete multipart uploads](src/main/java/com/example/s3/AbortMultipartUploadExamples.java)
- [Download S3 'directories'](src/main/java/com/example/s3/transfermanager/S3DirectoriesDownloader.java)
- [Download objects to a local directory](src/main/java/com/example/s3/transfermanager/DownloadToDirectory.java)
@@ -129,6 +130,18 @@ This example shows you how to do the following:
+#### Check if a bucket exists
+
+This example shows you how to check if a bucket exists.
+
+
+
+
+
+
+
+
+
#### Delete incomplete multipart uploads
This example shows you how to how to delete or stop incomplete Amazon S3 multipart uploads.
diff --git a/javav2/example_code/s3/src/main/java/com/example/s3/DoesBucketExist.java b/javav2/example_code/s3/src/main/java/com/example/s3/DoesBucketExist.java
new file mode 100644
index 00000000000..3b8f8ab20b3
--- /dev/null
+++ b/javav2/example_code/s3/src/main/java/com/example/s3/DoesBucketExist.java
@@ -0,0 +1,61 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+package com.example.s3;
+// snippet-start:[s3.java2.does-bucket-exist-main]
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.awssdk.awscore.exception.AwsServiceException;
+import software.amazon.awssdk.http.HttpStatusCode;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.utils.Validate;
+
+public class DoesBucketExist {
+ private static final Logger logger = LoggerFactory.getLogger(DoesBucketExist.class);
+
+ public static void main(String[] args) {
+ DoesBucketExist doesBucketExist = new DoesBucketExist();
+
+ final S3Client s3SyncClient = S3Client.builder().build();
+ final String bucketName = "amzn-s3-demo-bucket"; // Change to the bucket name that you want to check.
+
+ boolean exists = doesBucketExist.doesBucketExist(bucketName, s3SyncClient);
+ logger.info("Bucket exists: {}", exists);
+ }
+
+ /**
+ * Checks if the specified bucket exists. Amazon S3 buckets are named in a global namespace; use this method to
+ * determine if a specified bucket name already exists, and therefore can't be used to create a new bucket.
+ *
+ * Internally this method uses the S3Client.getBucketAcl(String)
+ * operation to determine whether the bucket exists.
+ *
+ * This method is equivalent to the AWS SDK for Java V1's AmazonS3Client#doesBucketExistV2(String).
+ *
+ * @param bucketName The name of the bucket to check.
+ * @param s3SyncClient An S3Client instance. The method checks for the bucket in the AWS Region
+ * configured on the instance.
+ * @return The value true if the specified bucket exists in Amazon S3; the value false if there is no bucket in
+ * Amazon S3 with that name.
+ */
+ public boolean doesBucketExist(String bucketName, S3Client s3SyncClient) {
+ try {
+ Validate.notEmpty(bucketName, "The bucket name must not be null or an empty string.", "");
+ s3SyncClient.getBucketAcl(r -> r.bucket(bucketName));
+ return true;
+ } catch (AwsServiceException ase) {
+ // A redirect error or an AccessDenied exception means the bucket exists but it's not in this region
+ // or we don't have permissions to it.
+ if ((ase.statusCode() == HttpStatusCode.MOVED_PERMANENTLY) || "AccessDenied".equals(ase.awsErrorDetails().errorCode())) {
+ return true;
+ }
+ if (ase.statusCode() == HttpStatusCode.NOT_FOUND) {
+ return false;
+ }
+ throw ase;
+ }
+ }
+}
+// snippet-end:[s3.java2.does-bucket-exist-main]
diff --git a/javav2/example_code/s3/src/main/java/com/example/s3/transfermanager/S3DirectoriesDownloader.java b/javav2/example_code/s3/src/main/java/com/example/s3/transfermanager/S3DirectoriesDownloader.java
index b81831a993d..d1efabfe168 100644
--- a/javav2/example_code/s3/src/main/java/com/example/s3/transfermanager/S3DirectoriesDownloader.java
+++ b/javav2/example_code/s3/src/main/java/com/example/s3/transfermanager/S3DirectoriesDownloader.java
@@ -42,7 +42,7 @@
public class S3DirectoriesDownloader {
private static final Logger logger = LoggerFactory.getLogger(S3DirectoriesDownloader.class);
- public final String bucketName = "amzn-s3-demo-bucket" + UUID.randomUUID(); // Change bucket name.
+ public final String bucketName = "junk-s3-demo-bucket" + UUID.randomUUID(); // Change bucket name.
public URI destinationPathURI;
private final Set downloadedFileNameSet = new HashSet<>();
private final String destinationDirName = "downloadDirectory";
diff --git a/javav2/example_code/s3/src/main/resources/xml_testing.xml b/javav2/example_code/s3/src/main/resources/xml_testing.xml
new file mode 100644
index 00000000000..5f1a0c3071d
--- /dev/null
+++ b/javav2/example_code/s3/src/main/resources/xml_testing.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ owner
+ dad784318ac45facc6a8c74b9b44f18afd317c85fa8776eeb2b000c8942bc8d9
+
+ FULL_CONTROL
+
+
+
+ my-grantee
+ http://acs.amazonaws.com/groups/global/AuthenticatedUsers
+
+ READ_ACP
+
+
+
+ dad784318ac45facc6a8c74b9b44f18afd317c85fa8776eeb2b000c8942bc8d9
+
+
\ No newline at end of file
diff --git a/javav2/example_code/s3/src/test/java/com/example/s3/DoesBucketExistTest.java b/javav2/example_code/s3/src/test/java/com/example/s3/DoesBucketExistTest.java
new file mode 100644
index 00000000000..a21c26047fc
--- /dev/null
+++ b/javav2/example_code/s3/src/test/java/com/example/s3/DoesBucketExistTest.java
@@ -0,0 +1,162 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+package com.example.s3;
+//
+
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import software.amazon.awssdk.policybuilder.iam.IamConditionKey;
+import software.amazon.awssdk.policybuilder.iam.IamConditionOperator;
+import software.amazon.awssdk.policybuilder.iam.IamEffect;
+import software.amazon.awssdk.policybuilder.iam.IamPolicy;
+import software.amazon.awssdk.policybuilder.iam.IamPrincipalType;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.iam.IamClient;
+import software.amazon.awssdk.services.iam.model.PutRolePolicyResponse;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.sts.StsClient;
+import software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider;
+
+import java.util.List;
+import java.util.UUID;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class DoesBucketExistTest {
+ private static final String ROLE_NAME = "minimal-s3-perms-role";
+ private static final String POLICY_NAME = "minimum-s3-ability-policy";
+ private static final IamClient iamClient = IamClient.builder().build();
+
+ @Test
+ @Tag("IntegrationTest")
+ void doesBucketExist_exists_but_not_in_client_region_should_return_true() {
+
+ S3Client usWestS3Client = S3Client.builder().region(Region.US_WEST_2).build();
+ final String bucketName = "my-us-west2-bucket-" + UUID.randomUUID();
+ createBucket(usWestS3Client, bucketName);
+
+ DoesBucketExist doesBucketExist = new DoesBucketExist();
+ S3Client euCentralS3Client = S3Client.builder().region(Region.EU_CENTRAL_1).build();
+ boolean exists = doesBucketExist.doesBucketExist(bucketName, euCentralS3Client);
+ assertTrue(exists);
+
+ deleteBucket(usWestS3Client, bucketName);
+ }
+
+ @Test
+ @Tag("IntegrationTest")
+ void doesBucketExist_does_not_exist_should_return_false() {
+
+ DoesBucketExist doesBucketExist = new DoesBucketExist();
+ final String bucketName = "xx-xx-xxxx-xxxx" + UUID.randomUUID();
+
+ boolean exists = doesBucketExist.doesBucketExist(bucketName, S3Client.create());
+ assertFalse(exists);
+ }
+
+ @Test
+ @Tag("IntegrationTest")
+ void doesBucketExist_returns_true_when_bucket_exists_but_caller_does_not_have_permission() {
+ StsClient stsClient = StsClient.create();
+ createAssumableRole(stsClient);
+
+ S3Client s3Client = S3Client.create();
+ final String bucketName = "my-bucket-" + UUID.randomUUID();
+ createBucket(s3Client, bucketName);
+
+ try {
+
+ String roleArn = iamClient.getRole(b -> b.roleName(ROLE_NAME)).role().arn();
+
+ S3Client s3ClientWithoutPermission = S3Client.builder()
+ .credentialsProvider(StsAssumeRoleCredentialsProvider.builder()
+ .stsClient(stsClient)
+ .refreshRequest(arr -> arr
+ .roleArn(roleArn)
+ .roleSessionName("test-session"))
+ .build())
+ .build();
+ DoesBucketExist doesBucketExist = new DoesBucketExist();
+ boolean existsButNoAccess = doesBucketExist.doesBucketExist(bucketName, s3ClientWithoutPermission);
+ assertTrue(existsButNoAccess);
+
+ boolean exists = doesBucketExist.doesBucketExist("non-existent-bucket" + UUID.randomUUID(), s3ClientWithoutPermission);
+ assertFalse(exists);
+ } finally {
+ deleteBucket(s3Client, bucketName);
+ deleteRole();
+
+ }
+ }
+
+ private static void createBucket(S3Client s3Client, String bucketName) {
+ s3Client.createBucket(b -> b.bucket(bucketName));
+ s3Client.waiter().waitUntilBucketExists(b -> b.bucket(bucketName));
+ }
+
+ private static void deleteBucket(S3Client s3Client, String bucketName) {
+ s3Client.deleteBucket(b -> b.bucket(bucketName));
+ s3Client.waiter().waitUntilBucketNotExists(b -> b.bucket(bucketName));
+ }
+
+
+ private static void createAssumableRole(StsClient stsClient) {
+ final String accountID = stsClient.getCallerIdentity().account();
+
+ IamPolicy trustIamPolicyForAnyoneInSameAccount = IamPolicy.builder()
+ .addStatement(statement -> statement
+ .effect(IamEffect.ALLOW)
+ .addPrincipal(principal -> principal
+ .type(IamPrincipalType.AWS)
+ .id("arn:aws:iam::" + accountID + ":root")
+ )
+ .addAction("sts:AssumeRole")
+ .addConditions(IamConditionOperator.STRING_EQUALS,
+ IamConditionKey.create("aws:PrincipalType"),
+ List.of("User", "AssumedRole")
+ ).addConditions(IamConditionOperator.STRING_LIKE,
+ "aws:userId",
+ List.of("AIDAX*", "AROA*:*", "AIDA*:*"))
+ )
+ .build();
+
+ iamClient.createRole(crb -> crb
+ .roleName(ROLE_NAME)
+ .assumeRolePolicyDocument(trustIamPolicyForAnyoneInSameAccount.toJson())
+ );
+
+ IamPolicy getBucketLocationOnlyPolicy = IamPolicy.builder()
+ .addStatement(statement -> statement
+ .effect(IamEffect.ALLOW)
+ .addAction("s3:GetBucketLocation")
+ .addResource("arn:aws:s3:::*")
+ )
+ .build();
+
+ iamClient.putRolePolicy(prprb -> prprb
+ .roleName(ROLE_NAME)
+ .policyName(POLICY_NAME)
+ .policyDocument(getBucketLocationOnlyPolicy.toJson()));
+
+ // Add a delay for the role to propagate.
+ try {
+ Thread.sleep(8000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ private static void deleteRole(){
+
+ iamClient.deleteRolePolicy(drbrb -> drbrb
+ .roleName(ROLE_NAME)
+ .policyName(POLICY_NAME));
+
+ iamClient.deleteRole(drb -> drb
+ .roleName(ROLE_NAME)
+ );
+ }
+}
+