diff --git a/src/examples/java/software/amazon/nio/spi/examples/CreateBucket.java b/src/examples/java/software/amazon/nio/spi/examples/CreateBucket.java
new file mode 100644
index 00000000..9ac6e69c
--- /dev/null
+++ b/src/examples/java/software/amazon/nio/spi/examples/CreateBucket.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package software.amazon.nio.spi.examples;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystems;
+import java.util.Map;
+
+public class CreateBucket {
+ public static void main(String[] args) throws IOException {
+ try (var fs = FileSystems.newFileSystem(URI.create(args[0]),
+ Map.of("locationConstraint", "us-east-1"))) {
+ System.out.println(fs.toString());
+ }
+ }
+}
diff --git a/src/main/java/software/amazon/nio/spi/s3/S3FileSystemProvider.java b/src/main/java/software/amazon/nio/spi/s3/S3FileSystemProvider.java
index e5a831b6..ce622c8f 100644
--- a/src/main/java/software/amazon/nio/spi/s3/S3FileSystemProvider.java
+++ b/src/main/java/software/amazon/nio/spi/s3/S3FileSystemProvider.java
@@ -55,6 +55,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.core.async.AsyncRequestBody;
+import software.amazon.awssdk.core.exception.SdkException;
+import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.model.ChecksumAlgorithm;
import software.amazon.awssdk.services.s3.model.CopyObjectRequest;
@@ -106,12 +108,75 @@ public String getScheme() {
}
/**
- * @throws NotYetImplementedException This method is not yet supported in v2.x. It might be implemented for bucket creation
+ *
+ * Experimental. Attempts to create a new S3 bucket based on the "authority" part of the URI and returns the
+ * {@code FileSystem} object identified by the URI.
+ *
+ * @param uri The URI to identify the file system
+ * @param env The environment to be used when creating the file system. May be null or empty.
+ * The following keys are supported:
+ *
+ * - acl
+ * - grantFullControl
+ * - grantRead
+ * - grantReadACP
+ * - grantWrite
+ * - grantWriteACP
+ * - locationConstraint
+ *
+ * The values should be @code{String}s or may be objects if the @code{toString()} method of those objects
+ * produce @code{String}s that would be accepted by the associated S3 create bucket builders. All other
+ * keys are currently ignored but future implementations may support additional keys and may also throw
+ * an @link{IllegalArgumentException} if they are not recognized.
+ * @return The new file system
+ * @since 2.0.0, the current implementation is experimental and may change in the future.
+ * @throws IOException If an exception occurs. In all cases the exception will wrap a causal exception which could be
+ * an SDKException thrown by the underlying S3 service or may be one of:
+ * ExecutionException, InterruptedException, or TimeoutException if a problem occurs with the
+ * asynchronous call to the service.
+ * @throws IllegalArgumentException if the URI scheme is not "s3".
*/
@Override
- public FileSystem newFileSystem(URI uri, Map env) {
- throw new NotYetImplementedException(
- "This method is not yet supported in v2.x. It might be implemented for bucket creation");
+ public FileSystem newFileSystem(final URI uri, final Map env) throws IOException {
+ if (! uri.getScheme().equals(SCHEME)) {
+ throw new IllegalArgumentException("URI scheme must be s3");
+ }
+
+ @SuppressWarnings("unchecked")
+ var envMap = (Map) env;
+
+ var bucketName = uri.getAuthority();
+ try (var client = S3AsyncClient.create()) {
+ var createBucketResponse = client.createBucket(
+ bucketBuilder -> bucketBuilder.bucket(bucketName)
+ .acl(envMap.getOrDefault("acl", "").toString())
+ .grantFullControl(envMap.getOrDefault("grantFullControl", "").toString())
+ .grantRead(envMap.getOrDefault("grantRead", "").toString())
+ .grantReadACP(envMap.getOrDefault("grantReadACP", "").toString())
+ .grantWrite(envMap.getOrDefault("grantWrite", "").toString())
+ .grantWriteACP(envMap.getOrDefault("grantWriteACP", "").toString())
+ .createBucketConfiguration(confBuilder -> {
+ if (envMap.containsKey("locationConstraint")) {
+ String loc = envMap.get("locationConstraint").toString();
+ if (loc.equals(Region.US_EAST_1.id())) {
+ loc = null; // us-east-1 is the default (null) location for S3
+ }
+ confBuilder.locationConstraint(loc);
+ }
+ })
+ ).get(30, TimeUnit.SECONDS);
+ logger.debug("Create bucket response {}", createBucketResponse.toString());
+
+ } catch (ExecutionException e) {
+ throw new IOException(e.getMessage(), e.getCause());
+ } catch (InterruptedException | TimeoutException | SdkException e) {
+ throw new IOException(e.getMessage(), e);
+ }
+
+
+ return getFileSystem(uri, true);
+
+
}
/**
diff --git a/src/test/java/software/amazon/nio/spi/s3/FileSystemsTest.java b/src/test/java/software/amazon/nio/spi/s3/FileSystemsTest.java
index d5acfe65..7696c2ec 100644
--- a/src/test/java/software/amazon/nio/spi/s3/FileSystemsTest.java
+++ b/src/test/java/software/amazon/nio/spi/s3/FileSystemsTest.java
@@ -5,27 +5,22 @@
package software.amazon.nio.spi.s3;
+import java.net.URI;
+import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
-import java.net.URI;
-import java.nio.file.FileSystems;
-import java.util.Collections;
-import java.util.stream.Stream;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
public class FileSystemsTest {
@ParameterizedTest
@MethodSource("uris")
@DisplayName("newFileSystem(URI, env) should throw")
public void newFileSystemURI(URI uri) {
- assertThatThrownBy(
- () -> FileSystems.newFileSystem(uri, Collections.emptyMap())
- ).isInstanceOf(NotYetImplementedException.class);
+// assertThatThrownBy(
+// () -> FileSystems.newFileSystem(uri, Collections.emptyMap())
+// ).isInstanceOf(NotYetImplementedException.class);
}
private static Stream uris() {
diff --git a/src/test/java/software/amazon/nio/spi/s3/S3FileSystemProviderTest.java b/src/test/java/software/amazon/nio/spi/s3/S3FileSystemProviderTest.java
index 5c0e7a89..98c9196d 100644
--- a/src/test/java/software/amazon/nio/spi/s3/S3FileSystemProviderTest.java
+++ b/src/test/java/software/amazon/nio/spi/s3/S3FileSystemProviderTest.java
@@ -104,14 +104,6 @@ public void getScheme() {
assertEquals("s3", provider.getScheme());
}
- @Test
- @DisplayName("newFileSystem(URI, env) should throw")
- public void newFileSystemURI() {
- assertThatThrownBy(
- () -> new S3FileSystemProvider().newFileSystem(URI.create(pathUri), Collections.emptyMap())
- ).isInstanceOf(NotYetImplementedException.class);
- }
-
@Test
@DisplayName("newFileSystem(Path, env) should throw")
public void newFileSystemPath() {
diff --git a/src/test/java/software/amazon/nio/spi/s3/S3XFileSystemProviderTest.java b/src/test/java/software/amazon/nio/spi/s3/S3XFileSystemProviderTest.java
index e8d6bbd5..deb8b4ca 100644
--- a/src/test/java/software/amazon/nio/spi/s3/S3XFileSystemProviderTest.java
+++ b/src/test/java/software/amazon/nio/spi/s3/S3XFileSystemProviderTest.java
@@ -42,14 +42,6 @@ public void nio_provider() {
then(path.getKey()).isEqualTo("myfolder");
}
- @Test
- @DisplayName("newFileSystem(URI, env) should throw")
- public void newFileSystemURI() {
- assertThatThrownBy(
- () -> new S3XFileSystemProvider().newFileSystem(URI1, Collections.emptyMap())
- ).isInstanceOf(NotYetImplementedException.class);
- }
-
@Test
@DisplayName("newFileSystem(Path, env) should throw")
public void newFileSystemPath() {