diff --git a/gcloud-java-examples/src/main/java/com/google/cloud/examples/storage/snippets/BlobSnippets.java b/gcloud-java-examples/src/main/java/com/google/cloud/examples/storage/snippets/BlobSnippets.java new file mode 100644 index 000000000000..2ffcd4dd5a38 --- /dev/null +++ b/gcloud-java-examples/src/main/java/com/google/cloud/examples/storage/snippets/BlobSnippets.java @@ -0,0 +1,231 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * EDITING INSTRUCTIONS + * This file is referenced in Blob's javadoc. Any change to this file should be reflected in Blob's + * javadoc. + */ + +package com.google.cloud.examples.storage.snippets; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.cloud.AuthCredentials; +import com.google.cloud.ReadChannel; +import com.google.cloud.ServiceAccountSigner; +import com.google.cloud.WriteChannel; +import com.google.cloud.storage.Blob; +import com.google.cloud.storage.Blob.BlobSourceOption; +import com.google.cloud.storage.BlobId; +import com.google.cloud.storage.CopyWriter; +import com.google.cloud.storage.Storage.SignUrlOption; +import com.google.cloud.storage.StorageException; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * This class contains a number of snippets for the {@link Blob} class. + */ +public class BlobSnippets { + + private final Blob blob; + + public BlobSnippets(Blob blob) { + this.blob = blob; + } + + /** + * Example of checking if the blob exists. + */ + // [TARGET exists(BlobSourceOption...)] + public boolean exists() { + // [START exists] + boolean exists = blob.exists(); + if (exists) { + // the blob exists + } else { + // the blob was not found + } + // [END exists] + return exists; + } + + /** + * Example of reading all bytes of the blob, if its generation matches the + * {@link Blob#generation()} value, otherwise a {@link StorageException} is thrown. + */ + // [TARGET content(BlobSourceOption...)] + public byte[] content() { + // [START content] + byte[] content = blob.content(BlobSourceOption.generationMatch()); + // [END content] + return content; + } + + /** + * Example of getting the blob's latest information, if its generation does not match the + * {@link Blob#generation()} value, otherwise a {@link StorageException} is thrown. + */ + // [TARGET reload(BlobSourceOption...)] + public Blob reload() { + // [START reload] + Blob latestBlob = blob.reload(BlobSourceOption.generationNotMatch()); + if (latestBlob == null) { + // the blob was not found + } + // [END reload] + return latestBlob; + } + + /** + * Example of replacing blob's metadata. + */ + // [TARGET update(BlobTargetOption...)] + public Blob update() { + // [START update] + Map newMetadata = new HashMap<>(); + newMetadata.put("key", "value"); + blob.toBuilder().metadata(null).build().update(); + Blob updatedBlob = blob.toBuilder().metadata(newMetadata).build().update(); + // [END update] + return updatedBlob; + } + + /** + * Example of deleting the blob, if its generation matches the {@link Blob#generation()} value, + * otherwise a {@link StorageException} is thrown. + */ + // [TARGET delete(BlobSourceOption...)] + public boolean delete() { + // [START delete] + boolean deleted = blob.delete(BlobSourceOption.generationMatch()); + if (deleted) { + // the blob was deleted + } else { + // the blob was not found + } + // [END delete] + return deleted; + } + + /** + * Example of copying the blob to a different bucket with a different name. + */ + // [TARGET copyTo(BlobId, BlobSourceOption...)] + // [VARIABLE "my_unique_bucket"] + // [VARIABLE "copy_blob_name"] + public Blob copyToId(String bucketName, String blobName) { + // [START copyToId] + CopyWriter copyWriter = blob.copyTo(BlobId.of(bucketName, blobName)); + Blob copiedBlob = copyWriter.result(); + // [END copyToId] + return copiedBlob; + } + + /** + * Example of copying the blob to a different bucket, keeping the original name. + */ + // [TARGET copyTo(String, BlobSourceOption...)] + // [VARIABLE "my_unique_bucket"] + public Blob copyToBucket(String bucketName) { + // [START copyToBucket] + CopyWriter copyWriter = blob.copyTo(bucketName); + Blob copiedBlob = copyWriter.result(); + // [END copyToBucket] + return copiedBlob; + } + + /** + * Example of copying the blob to a different bucket with a different name. + */ + // [TARGET copyTo(String, String, BlobSourceOption...)] + // [VARIABLE "my_unique_bucket"] + // [VARIABLE "copy_blob_name"] + public Blob copyToStrings(String bucketName, String blobName) { + // [START copyToStrings] + CopyWriter copyWriter = blob.copyTo(bucketName, blobName); + Blob copiedBlob = copyWriter.result(); + // [END copyToStrings] + return copiedBlob; + } + + /** + * Example of reading the blob's content through a reader. + */ + // [TARGET reader(BlobSourceOption...)] + public void reader() throws IOException { + // [START reader] + try (ReadChannel reader = blob.reader()) { + ByteBuffer bytes = ByteBuffer.allocate(64 * 1024); + while (reader.read(bytes) > 0) { + bytes.flip(); + // do something with bytes + bytes.clear(); + } + } + // [END reader] + } + + /** + * Example of writing the blob's content through a writer. + */ + // [TARGET writer(BlobWriteOption...)] + public void writer() throws IOException { + // [START writer] + byte[] content = "Hello, World!".getBytes(UTF_8); + try (WriteChannel writer = blob.writer()) { + try { + writer.write(ByteBuffer.wrap(content, 0, content.length)); + } catch (Exception ex) { + // handle exception + } + } + // [END writer] + } + + /** + * Example of creating a signed URL for the blob that is valid for 2 weeks, using the default + * credentials for signing the URL. + */ + // [TARGET signUrl(long, TimeUnit, SignUrlOption...)] + public URL signUrl() { + // [START signUrl] + URL signedUrl = blob.signUrl(14, TimeUnit.DAYS); + // [END signUrl] + return signedUrl; + } + + /** + * Example of creating a signed URL for the blob passing the + * {@link SignUrlOption#signWith(ServiceAccountSigner)} option, that will be used to sign the URL. + */ + // [TARGET signUrl(long, TimeUnit, SignUrlOption...)] + // [VARIABLE "/path/to/key.json"] + public URL signUrlWithSigner(String keyPath) throws IOException { + // [START signUrlWithSigner] + URL signedUrl = blob.signUrl(14, TimeUnit.DAYS, SignUrlOption.signWith( + AuthCredentials.createForJson(new FileInputStream(keyPath)))); + // [END signUrlWithSigner] + return signedUrl; + } +} diff --git a/gcloud-java-examples/src/test/java/com/google/cloud/example/storage/snippets/ITBlobSnippets.java b/gcloud-java-examples/src/test/java/com/google/cloud/example/storage/snippets/ITBlobSnippets.java new file mode 100644 index 000000000000..39c3e5d5b6db --- /dev/null +++ b/gcloud-java-examples/src/test/java/com/google/cloud/example/storage/snippets/ITBlobSnippets.java @@ -0,0 +1,123 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.example.storage.snippets; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.google.cloud.examples.storage.snippets.BlobSnippets; +import com.google.cloud.storage.Blob; +import com.google.cloud.storage.BlobId; +import com.google.cloud.storage.BlobInfo; +import com.google.cloud.storage.BucketInfo; +import com.google.cloud.storage.Storage; +import com.google.cloud.storage.StorageException; +import com.google.cloud.storage.testing.RemoteStorageHelper; +import com.google.common.collect.ImmutableMap; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class ITBlobSnippets { + + private static final Logger log = Logger.getLogger(ITBlobSnippets.class.getName()); + private static final String BUCKET = RemoteStorageHelper.generateBucketName(); + private static final String BLOB = "blob"; + private static final byte[] EMPTY_CONTENT = new byte[0]; + private static final byte[] CONTENT = "Hello, World!".getBytes(UTF_8); + + private static Storage storage; + private static Blob blob; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @BeforeClass + public static void beforeClass() { + RemoteStorageHelper helper = RemoteStorageHelper.create(); + storage = helper.options().service(); + storage.create(BucketInfo.of(BUCKET)); + blob = storage.create(BlobInfo.builder(BUCKET, BLOB).build()); + } + + @AfterClass + public static void afterClass() throws ExecutionException, InterruptedException { + if (storage != null) { + boolean wasDeleted = RemoteStorageHelper.forceDelete(storage, BUCKET, 5, TimeUnit.SECONDS); + if (!wasDeleted && log.isLoggable(Level.WARNING)) { + log.log(Level.WARNING, "Deletion of bucket {0} timed out, bucket is not empty", BUCKET); + } + } + } + + @Test + public void testBlob() throws IOException { + BlobSnippets blobSnippets = new BlobSnippets(blob); + assertTrue(blobSnippets.exists()); + assertArrayEquals(EMPTY_CONTENT, blobSnippets.content()); + try { + assertNotNull(blobSnippets.reload()); + fail("Expected StorageException to be thrown"); + } catch (StorageException ex) { + // expected + } + Blob updatedBlob = blobSnippets.update(); + assertEquals(ImmutableMap.of("key", "value"), updatedBlob.metadata()); + Blob copiedBlob = blobSnippets.copyToStrings(BUCKET, "copyBlob"); + assertNotNull(copiedBlob); + copiedBlob.delete(); + copiedBlob = blobSnippets.copyToId(BUCKET, "copyBlob"); + assertNotNull(copiedBlob); + copiedBlob.delete(); + copiedBlob = blobSnippets.copyToBucket(BUCKET); + assertNotNull(copiedBlob); + blobSnippets.reload(); + blobSnippets.writer(); + URL signedUrl = blobSnippets.signUrl(); + URLConnection connection = signedUrl.openConnection(); + byte[] readBytes = new byte[CONTENT.length]; + try (InputStream responseStream = connection.getInputStream()) { + assertEquals(CONTENT.length, responseStream.read(readBytes)); + assertArrayEquals(CONTENT, readBytes); + } + signedUrl = blobSnippets.signUrlWithSigner(System.getenv("GOOGLE_APPLICATION_CREDENTIALS")); + connection = signedUrl.openConnection(); + try (InputStream responseStream = connection.getInputStream()) { + assertEquals(CONTENT.length, responseStream.read(readBytes)); + assertArrayEquals(CONTENT, readBytes); + } + assertFalse(blobSnippets.delete()); + storage.delete(BlobId.of(BUCKET, BLOB)); + } +} diff --git a/gcloud-java-storage/src/main/java/com/google/cloud/storage/Blob.java b/gcloud-java-storage/src/main/java/com/google/cloud/storage/Blob.java index 3cbb3826541f..139313ad835e 100644 --- a/gcloud-java-storage/src/main/java/com/google/cloud/storage/Blob.java +++ b/gcloud-java-storage/src/main/java/com/google/cloud/storage/Blob.java @@ -322,6 +322,16 @@ public Blob build() { /** * Checks if this blob exists. * + *

Example of checking if the blob exists. + *

 {@code
+   * boolean exists = blob.exists();
+   * if (exists) {
+   *   // the blob exists
+   * } else {
+   *   // the blob was not found
+   * }
+   * }
+ * * @param options blob read options * @return true if this blob exists, false otherwise * @throws StorageException upon failure @@ -336,16 +346,31 @@ public boolean exists(BlobSourceOption... options) { /** * Returns this blob's content. * + *

Example of reading all bytes of the blob, if its generation matches the + * {@link Blob#generation()} value, otherwise a {@link StorageException} is thrown. + *

 {@code
+   * byte[] content = blob.content(BlobSourceOption.generationMatch());
+   * }
+ * * @param options blob read options * @throws StorageException upon failure */ - public byte[] content(Storage.BlobSourceOption... options) { - return storage.readAllBytes(blobId(), options); + public byte[] content(BlobSourceOption... options) { + return storage.readAllBytes(blobId(), toSourceOptions(this, options)); } /** * Fetches current blob's latest information. Returns {@code null} if the blob does not exist. * + *

Example of getting the blob's latest information, if its generation does not match the + * {@link Blob#generation()} value, otherwise a {@link StorageException} is thrown. + *

 {@code
+   * Blob latestBlob = blob.reload(BlobSourceOption.generationNotMatch());
+   * if (latestBlob == null) {
+   *   // the blob was not found
+   * }
+   * }
+ * * @param options blob read options * @return a {@code Blob} object with latest information or {@code null} if not found * @throws StorageException upon failure @@ -367,12 +392,13 @@ public Blob reload(BlobSourceOption... options) { * {@code blob}'s metadata to {@code null}. *

* - *

Example usage of replacing blob's metadata: + *

Example of replacing blob's metadata. *

 {@code
+   * Map newMetadata = new HashMap<>();
+   * newMetadata.put("key", "value");
    * blob.toBuilder().metadata(null).build().update();
-   * blob.toBuilder().metadata(newMetadata).build().update();
-   * }
-   * 
+ * Blob updatedBlob = blob.toBuilder().metadata(newMetadata).build().update(); + * } * * @param options update options * @return a {@code Blob} object with updated information @@ -385,6 +411,17 @@ public Blob update(BlobTargetOption... options) { /** * Deletes this blob. * + *

Example of deleting the blob, if its generation matches the {@link Blob#generation()} value, + * otherwise a {@link StorageException} is thrown. + *

 {@code
+   * boolean deleted = blob.delete(BlobSourceOption.generationMatch());
+   * if (deleted) {
+   *   // the blob was deleted
+   * } else {
+   *   // the blob was not found
+   * }
+   * }
+ * * @param options blob delete options * @return {@code true} if blob was deleted, {@code false} if it was not found * @throws StorageException upon failure @@ -397,6 +434,14 @@ public boolean delete(BlobSourceOption... options) { * Sends a copy request for the current blob to the target blob. Possibly also some of the * metadata are copied (e.g. content-type). * + *

Example of copying the blob to a different bucket with a different name. + *

 {@code
+   * String bucketName = "my_unique_bucket";
+   * String blobName = "copy_blob_name";
+   * CopyWriter copyWriter = blob.copyTo(BlobId.of(bucketName, blobName));
+   * Blob copiedBlob = copyWriter.result();
+   * }
+ * * @param targetBlob target blob's id * @param options source blob options * @return a {@link CopyWriter} object that can be used to get information on the newly created @@ -416,6 +461,13 @@ public CopyWriter copyTo(BlobId targetBlob, BlobSourceOption... options) { * Sends a copy request for the current blob to the target bucket, preserving its name. Possibly * copying also some of the metadata (e.g. content-type). * + *

Example of copying the blob to a different bucket, keeping the original name. + *

 {@code
+   * String bucketName = "my_unique_bucket";
+   * CopyWriter copyWriter = blob.copyTo(bucketName);
+   * Blob copiedBlob = copyWriter.result();
+   * }
+ * * @param targetBucket target bucket's name * @param options source blob options * @return a {@link CopyWriter} object that can be used to get information on the newly created @@ -430,6 +482,14 @@ public CopyWriter copyTo(String targetBucket, BlobSourceOption... options) { * Sends a copy request for the current blob to the target blob. Possibly also some of the * metadata are copied (e.g. content-type). * + *

Example of copying the blob to a different bucket with a different name. + *

 {@code
+   * String bucketName = "my_unique_bucket";
+   * String blobName = "copy_blob_name";
+   * CopyWriter copyWriter = blob.copyTo(bucketName, blobName);
+   * Blob copiedBlob = copyWriter.result();
+   * }
+ * * @param targetBucket target bucket's name * @param targetBlob target blob's name * @param options source blob options @@ -444,6 +504,18 @@ public CopyWriter copyTo(String targetBucket, String targetBlob, BlobSourceOptio /** * Returns a {@code ReadChannel} object for reading this blob's content. * + *

Example of reading the blob's content through a reader. + *

 {@code
+   * try (ReadChannel reader = blob.reader()) {
+   *   ByteBuffer bytes = ByteBuffer.allocate(64 * 1024);
+   *   while (reader.read(bytes) > 0) {
+   *     bytes.flip();
+   *     // do something with bytes
+   *     bytes.clear();
+   *   }
+   * }
+   * }
+ * * @param options blob read options * @throws StorageException upon failure */ @@ -456,6 +528,18 @@ public ReadChannel reader(BlobSourceOption... options) { * crc32c values in the current blob are ignored unless requested via the * {@code BlobWriteOption.md5Match} and {@code BlobWriteOption.crc32cMatch} options. * + *

Example of writing the blob's content through a writer. + *

 {@code
+   * byte[] content = "Hello, World!".getBytes(UTF_8);
+   * try (WriteChannel writer = blob.writer()) {
+   *   try {
+   *     writer.write(ByteBuffer.wrap(content, 0, content.length));
+   *   } catch (Exception ex) {
+   *     // handle exception
+   *   }
+   * }
+   * }
+ * * @param options target blob options * @throws StorageException upon failure */ @@ -485,18 +569,18 @@ public WriteChannel writer(BlobWriteOption... options) { *
  • The default credentials, if no credentials were passed to {@link StorageOptions} * * - *

    Example usage of creating a signed URL that is valid for 2 weeks, using the default - * credentials for signing the URL: + *

    Example of creating a signed URL for the blob that is valid for 2 weeks, using the default + * credentials for signing the URL. *

     {@code
    -   * blob.signUrl(14, TimeUnit.DAYS);
    +   * URL signedUrl = blob.signUrl(14, TimeUnit.DAYS);
        * }
    * - *

    Example usage of creating a signed URL passing the - * {@link SignUrlOption#signWith(ServiceAccountSigner)} option, that will be used for signing the - * URL: + *

    Example of creating a signed URL for the blob passing the + * {@link SignUrlOption#signWith(ServiceAccountSigner)} option, that will be used to sign the URL. *

     {@code
    -   * blob.signUrl(14, TimeUnit.DAYS, SignUrlOption.signWith(
    -   *     AuthCredentials.createForJson(new FileInputStream("/path/to/key.json"))));
    +   * String keyPath = "/path/to/key.json";
    +   * URL signedUrl = blob.signUrl(14, TimeUnit.DAYS, SignUrlOption.signWith(
    +   *     AuthCredentials.createForJson(new FileInputStream(keyPath))));
        * }
    * * @param duration time until the signed URL expires, expressed in {@code unit}. The finer