Skip to content

Commit 67fcb5b

Browse files
Improve NIO documentation
Documentation has been added to many methods to clarify the preferred method for instantiating the library, which is the non-SPI version.
1 parent 867278a commit 67fcb5b

File tree

5 files changed

+72
-41
lines changed

5 files changed

+72
-41
lines changed

gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageConfiguration.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ public static final class Builder {
8282
private int blockSize = CloudStorageFileSystem.BLOCK_SIZE_DEFAULT;
8383

8484
/**
85-
* Changes current working directory for new filesystem. This cannot be changed once it's
86-
* been set. You'll need to create another {@link CloudStorageFileSystem} object.
85+
* Changes current working directory for new filesystem. This defaults to the root directory.
86+
* The working directory cannot be changed once it's been set. You'll need to create another
87+
* {@link CloudStorageFileSystem} object.
8788
*
8889
* @throws IllegalArgumentException if {@code path} is not absolute.
8990
*/
@@ -95,7 +96,7 @@ public Builder workingDirectory(String path) {
9596

9697
/**
9798
* Configures whether or not we should throw an exception when encountering object names
98-
* containing superfluous slashes, e.g. {@code a//b}
99+
* containing superfluous slashes, e.g. {@code a//b}.
99100
*/
100101
public Builder permitEmptyPathComponents(boolean value) {
101102
permitEmptyPathComponents = value;

gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystem.java

+24-6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
import javax.annotation.Nullable;
3939
import javax.annotation.concurrent.Immutable;
40+
import javax.annotation.CheckReturnValue;
41+
import javax.annotation.concurrent.ThreadSafe;
4042

4143
/**
4244
* Google Cloud Storage {@link FileSystem} implementation.
@@ -46,7 +48,7 @@
4648
* @see <a href="https://developers.google.com/storage/docs/bucketnaming">
4749
* Bucket and Object Naming Guidelines</a>
4850
*/
49-
@Immutable
51+
@ThreadSafe
5052
public final class CloudStorageFileSystem extends FileSystem {
5153

5254
/**
@@ -64,6 +66,7 @@ public final class CloudStorageFileSystem extends FileSystem {
6466
* @see #forBucket(String, CloudStorageConfiguration)
6567
* @see java.nio.file.FileSystems#getFileSystem(URI)
6668
*/
69+
@CheckReturnValue
6770
public static CloudStorageFileSystem forBucket(String bucket) {
6871
return forBucket(bucket, CloudStorageConfiguration.DEFAULT);
6972
}
@@ -73,16 +76,26 @@ public static CloudStorageFileSystem forBucket(String bucket) {
7376
*
7477
* @see #forBucket(String)
7578
*/
79+
@CheckReturnValue
7680
public static CloudStorageFileSystem forBucket(String bucket, CloudStorageConfiguration config) {
7781
return forBucket(bucket, config, null);
7882
}
7983

8084
/**
81-
* Creates a new filesystem for a particular bucket, with customizable settings and storage
82-
* options.
85+
* Returns Google Cloud Storage {@link FileSystem} object for {@code bucket}.
8386
*
84-
* @see #forBucket(String)
87+
* <p>GCS file system objects are basically free. You can create as many as you want, even if you
88+
* have multiple instances for the same bucket. There's no actual system resources associated
89+
* with this object. Therefore calling {@link #close()} on the returned value is optional.
90+
*
91+
* <p><b>Note:</b> It is also possible to instantiate this class via Java's
92+
* {@code FileSystems.getFileSystem(URI.create("gs://bucket"))}. We discourage you
93+
* from using that if possible, for the reasons documented in
94+
* {@link CloudStorageFileSystemProvider#newFileSystem(URI, java.util.Map)}
95+
*
96+
* @see java.nio.file.FileSystems#getFileSystem(URI)
8597
*/
98+
@CheckReturnValue
8699
public static CloudStorageFileSystem forBucket(String bucket, CloudStorageConfiguration config,
87100
@Nullable StorageOptions storageOptions) {
88101
checkArgument(!bucket.startsWith(URI_SCHEME + ":"),
@@ -142,7 +155,9 @@ public CloudStoragePath getPath(String first, String... more) {
142155
}
143156

144157
/**
145-
* Does nothing.
158+
* Does nothing currently. This method <i>might</i> be updated in the future to close all channels
159+
* associated with this file system object. However it's unlikely that even then, calling this
160+
* method will become mandatory.
146161
*/
147162
@Override
148163
public void close() throws IOException {
@@ -178,6 +193,9 @@ public Iterable<Path> getRootDirectories() {
178193
return ImmutableSet.<Path>of(CloudStoragePath.getPath(this, UnixPath.ROOT));
179194
}
180195

196+
/**
197+
* Returns nothing because GCS doesn't have disk partitions of limited size, or anything similar.
198+
*/
181199
@Override
182200
public Iterable<FileStore> getFileStores() {
183201
return ImmutableSet.of();
@@ -193,7 +211,7 @@ public Set<String> supportedFileAttributeViews() {
193211
*/
194212
@Override
195213
public PathMatcher getPathMatcher(String syntaxAndPattern) {
196-
// TODO: Implement me.
214+
// TODO(#813): Implement me.
197215
throw new UnsupportedOperationException();
198216
}
199217

gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java

+19-6
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,16 @@
6969
import java.util.Set;
7070
import javax.annotation.Nullable;
7171
import javax.annotation.concurrent.ThreadSafe;
72+
import javax.inject.Singleton;
7273

7374
/**
7475
* Google Cloud Storage {@link FileSystemProvider} implementation.
76+
*
77+
* <p><b>Note:</b> This class should never be used directly. This class is instantiated by the
78+
* service loader and called through a standardized API, e.g. {@link java.nio.file.Files}. However
79+
* the javadocs in this class serve as useful documentation for the behavior of the GCS NIO library.
7580
*/
81+
@Singleton
7682
@ThreadSafe
7783
@AutoService(FileSystemProvider.class)
7884
public final class CloudStorageFileSystemProvider extends FileSystemProvider {
@@ -156,6 +162,13 @@ public CloudStorageFileSystem getFileSystem(URI uri) {
156162

157163
/**
158164
* Returns Cloud Storage file system, provided a URI with no path, e.g. {@code gs://bucket}.
165+
*
166+
* @param uri bucket and current working directory, e.g. {@code gs://bucket}
167+
* @param env map of configuration options, whose keys correspond to the method names of
168+
* {@link CloudStorageConfiguration.Builder}. However you are not allowed to set the working
169+
* directory, as that should be provided in the {@code uri}
170+
* @throws IllegalArgumentException if {@code uri} specifies a user, query, fragment, or scheme is
171+
* not {@value CloudStorageFileSystem#URI_SCHEME}
159172
*/
160173
@Override
161174
public CloudStorageFileSystem newFileSystem(URI uri, Map<String, ?> env) {
@@ -531,9 +544,9 @@ public <A extends BasicFileAttributes> A readAttributes(
531544

532545
@Override
533546
public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options) {
534-
// Java 7 NIO defines at least eleven string attributes we'd want to support
535-
// (eg. BasicFileAttributeView and PosixFileAttributeView), so rather than a partial
536-
// implementation we rely on the other overload for now.
547+
// TODO(#811): Java 7 NIO defines at least eleven string attributes we'd want to support
548+
// (eg. BasicFileAttributeView and PosixFileAttributeView), so rather than a partial
549+
// implementation we rely on the other overload for now.
537550
throw new UnsupportedOperationException();
538551
}
539552

@@ -615,13 +628,13 @@ public String toString() {
615628
}
616629

617630
private IOException asIOException(StorageException oops) {
631+
// RPC API can only throw StorageException, but CloudStorageFileSystemProvider
632+
// can only throw IOException. Square peg, round hole.
633+
// TODO(#810): Research if other codes should be translated similarly.
618634
if (oops.code() == 404) {
619635
return new NoSuchFileException(oops.reason());
620636
}
621-
// TODO: research if other codes should be translated to IOException.
622637

623-
// RPC API can only throw StorageException, but CloudStorageFileSystemProvider
624-
// can only throw IOException. Square peg, round hole.
625638
Throwable cause = oops.getCause();
626639
try {
627640
if (cause instanceof FileAlreadyExistsException) {

gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/cloud/storage/contrib/nio/it/ITGcsNio.java

+13-15
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,16 @@
5959

6060

6161
/**
62-
* Integration test for gcloud-nio. This test actually talks to GCS (you need an account).
63-
* Tests both reading and writing.
62+
* Integration test for gcloud-nio.
6463
*
65-
* You *must* set the GOOGLE_APPLICATION_CREDENTIALS environment variable
66-
* for this test to work. It must contain the name of a local file that contains
67-
* your Service Account JSON Key.
64+
* <p>This test actually talks to GCS (you need an account) and tests both reading and writing. You
65+
* *must* set the {@code GOOGLE_APPLICATION_CREDENTIALS} environment variable for this test to work.
66+
* It must contain the name of a local file that contains your Service Account JSON Key.
6867
*
69-
* The instructions for how to get the Service Account JSON Key are
68+
* <p>The instructions for how to get the Service Account JSON Key are
7069
* at https://cloud.google.com/storage/docs/authentication?hl=en#service_accounts
7170
*
72-
* The short version is this: go to cloud.google.com/console,
71+
* <p>The short version is this: go to cloud.google.com/console,
7372
* select your project, search for "API manager", click "Credentials",
7473
* click "create credentials/service account key", new service account,
7574
* JSON. The contents of the file that's sent to your browsers is your
@@ -79,19 +78,18 @@
7978
@RunWith(JUnit4.class)
8079
public class ITGcsNio {
8180

82-
private static final List<String> FILE_CONTENTS = ImmutableList.of(
83-
"Tous les êtres humains naissent libres et égaux en dignité et en droits.",
84-
"Ils sont doués de raison et de conscience et doivent agir ",
85-
"les uns envers les autres dans un esprit de fraternité.");
81+
private static final List<String> FILE_CONTENTS =
82+
ImmutableList.of(
83+
"Tous les êtres humains naissent libres et égaux en dignité et en droits.",
84+
"Ils sont doués de raison et de conscience et doivent agir ",
85+
"les uns envers les autres dans un esprit de fraternité.");
8686

8787
private static final Logger log = Logger.getLogger(ITGcsNio.class.getName());
8888
private static final String BUCKET = RemoteStorageHelper.generateBucketName();
8989
private static final String SML_FILE = "tmp-test-small-file.txt";
9090
private static final int SML_SIZE = 100;
91-
// it's big, relatively speaking.
92-
private static final String BIG_FILE = "tmp-test-big-file.txt";
93-
// arbitrary size that's not too round.
94-
private static final int BIG_SIZE = 2 * 1024 * 1024 - 50;
91+
private static final String BIG_FILE = "tmp-test-big-file.txt"; // it's big, relatively speaking.
92+
private static final int BIG_SIZE = 2 * 1024 * 1024 - 50; // arbitrary size that's not too round.
9593
private static final String PREFIX = "tmp-test-file";
9694
private static Storage storage;
9795
private static StorageOptions storageOptions;

gcloud-java-storage/src/main/java/com/google/cloud/storage/testing/FakeStorageRpc.java

+12-11
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,15 @@
5858
* <li>patch
5959
* <li>continueRewrite
6060
* <li>createBatch
61+
* <li>checksums, etags
6162
* </ul>
6263
* </ul>
6364
*/
6465
@NotThreadSafe
6566
public class FakeStorageRpc implements StorageRpc {
6667

6768
// fullname -> metadata
68-
Map<String, StorageObject> stuff = new HashMap<>();
69+
Map<String, StorageObject> metadata = new HashMap<>();
6970
// fullname -> contents
7071
Map<String, byte[]> contents = new HashMap<>();
7172
// fullname -> future contents that will be visible on close.
@@ -74,15 +75,15 @@ public class FakeStorageRpc implements StorageRpc {
7475
private final boolean throwIfOption;
7576

7677
/**
77-
* @param throwIfOption if true, we throw when given any option.
78+
* @param throwIfOption if true, we throw when given any option
7879
*/
7980
public FakeStorageRpc(boolean throwIfOption) {
8081
this.throwIfOption = throwIfOption;
8182
}
8283

8384
// remove all files
8485
void reset() {
85-
stuff = new HashMap<>();
86+
metadata = new HashMap<>();
8687
contents = new HashMap<>();
8788
}
8889

@@ -96,7 +97,7 @@ public StorageObject create(StorageObject object, InputStream content, Map<Optio
9697
throws StorageException {
9798
potentiallyThrow(options);
9899
String key = fullname(object);
99-
stuff.put(key, object);
100+
metadata.put(key, object);
100101
try {
101102
contents.put(key, com.google.common.io.ByteStreams.toByteArray(content));
102103
} catch (IOException e) {
@@ -138,7 +139,7 @@ public Tuple<String, Iterable<StorageObject>> list(String bucket, Map<Option, ?>
138139

139140
List<StorageObject> values = new ArrayList<>();
140141
Map<String, StorageObject> folders = new HashMap<>();
141-
for (StorageObject so : stuff.values()) {
142+
for (StorageObject so : metadata.values()) {
142143
if (!so.getName().startsWith(prefix)) {
143144
continue;
144145
}
@@ -175,8 +176,8 @@ public StorageObject get(StorageObject object, Map<Option, ?> options) throws St
175176
}
176177

177178
String key = fullname(object);
178-
if (stuff.containsKey(key)) {
179-
StorageObject ret = stuff.get(key);
179+
if (metadata.containsKey(key)) {
180+
StorageObject ret = metadata.get(key);
180181
if (contents.containsKey(key)) {
181182
ret.setSize(BigInteger.valueOf(contents.get(key).length));
182183
}
@@ -208,7 +209,7 @@ public boolean delete(Bucket bucket, Map<Option, ?> options) throws StorageExcep
208209
public boolean delete(StorageObject object, Map<Option, ?> options) throws StorageException {
209210
String key = fullname(object);
210211
contents.remove(key);
211-
return null != stuff.remove(key);
212+
return null != metadata.remove(key);
212213
}
213214

214215
@Override
@@ -272,10 +273,10 @@ public String open(StorageObject object, Map<Option, ?> options) throws StorageE
272273
}
273274
}
274275
}
275-
if (mustNotExist && stuff.containsKey(key)) {
276+
if (mustNotExist && metadata.containsKey(key)) {
276277
throw new StorageException(new FileAlreadyExistsException(key));
277278
}
278-
stuff.put(key, object);
279+
metadata.put(key, object);
279280

280281
return fullname(object);
281282
}
@@ -327,7 +328,7 @@ public RewriteResponse openRewrite(RewriteRequest rewriteRequest) throws Storage
327328
throw new StorageException(new FileAlreadyExistsException(destKey));
328329
}
329330

330-
stuff.put(destKey, rewriteRequest.target);
331+
metadata.put(destKey, rewriteRequest.target);
331332

332333
byte[] data = contents.get(sourceKey);
333334
contents.put(destKey, Arrays.copyOf(data, data.length));

0 commit comments

Comments
 (0)