From 339f172f6008f08d534fc64e9ceaec2d6514bcd1 Mon Sep 17 00:00:00 2001 From: Shin Fan Date: Tue, 7 Mar 2017 13:44:03 -0800 Subject: [PATCH] POSC support for Storage (#1670) --- .../storage/snippets/StorageSnippets.java | 3 +- .../java/com/google/cloud/storage/Blob.java | 6 +++ .../com/google/cloud/storage/BlobInfo.java | 30 ++++++++++++ .../java/com/google/cloud/storage/Bucket.java | 2 +- .../com/google/cloud/storage/BucketInfo.java | 14 +++--- .../com/google/cloud/storage/Storage.java | 2 +- .../google/cloud/storage/StorageClass.java | 48 +++++++++++++++++++ .../google/cloud/storage/BlobInfoTest.java | 6 +++ .../google/cloud/storage/BucketInfoTest.java | 2 +- .../com/google/cloud/storage/BucketTest.java | 2 +- .../cloud/storage/it/ITStorageTest.java | 24 ++++++++++ 11 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 google-cloud-storage/src/main/java/com/google/cloud/storage/StorageClass.java diff --git a/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java b/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java index e0b78afc9292..0355663786c6 100644 --- a/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java +++ b/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java @@ -53,6 +53,7 @@ import com.google.cloud.storage.Storage.SignUrlOption; import com.google.cloud.storage.StorageBatch; import com.google.cloud.storage.StorageBatchResult; +import com.google.cloud.storage.StorageClass; import com.google.cloud.storage.StorageException; import java.io.ByteArrayInputStream; @@ -100,7 +101,7 @@ public Bucket createBucketWithStorageClassAndLocation(String bucketName) { // [START createBucketWithStorageClassAndLocation] Bucket bucket = storage.create(BucketInfo.newBuilder(bucketName) // See here for possible values: http://g.co/cloud/storage/docs/storage-classes - .setStorageClass("COLDLINE") + .setStorageClass(StorageClass.COLDLINE) // Possible values: http://g.co/cloud/storage/docs/bucket-locations#location-mr .setLocation("asia") .build()); diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java index f188938381b3..327d22578d8c 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java @@ -302,6 +302,12 @@ public Builder setMetadata(Map metadata) { return this; } + @Override + public Builder setStorageClass(StorageClass storageClass) { + infoBuilder.setStorageClass(storageClass); + return this; + } + @Override Builder setMetageneration(Long metageneration) { infoBuilder.setMetageneration(metageneration); diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java index b15fe6e34fde..f191ab5f914f 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java @@ -24,6 +24,7 @@ import com.google.api.services.storage.model.ObjectAccessControl; import com.google.api.services.storage.model.StorageObject; import com.google.api.services.storage.model.StorageObject.Owner; +import com.google.cloud.storage.Blob.Builder; import com.google.common.base.Function; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; @@ -78,6 +79,7 @@ public StorageObject apply(BlobInfo blobInfo) { private final String contentEncoding; private final String contentDisposition; private final String contentLanguage; + private final StorageClass storageClass; private final Integer componentCount; private final boolean isDirectory; private final CustomerEncryption customerEncryption; @@ -242,6 +244,11 @@ public abstract static class Builder { abstract Builder setMediaLink(String mediaLink); + /** + * Sets the blob's storage class. + */ + public abstract Builder setStorageClass(StorageClass storageClass); + /** * Sets the blob's user provided metadata. */ @@ -290,6 +297,7 @@ static final class BuilderImpl extends Builder { private Long createTime; private Boolean isDirectory; private CustomerEncryption customerEncryption; + private StorageClass storageClass; BuilderImpl(BlobId blobId) { this.blobId = blobId; @@ -319,6 +327,7 @@ static final class BuilderImpl extends Builder { updateTime = blobInfo.updateTime; createTime = blobInfo.createTime; isDirectory = blobInfo.isDirectory; + storageClass = blobInfo.storageClass; } @Override @@ -424,6 +433,12 @@ public Builder setMetadata(Map metadata) { return this; } + @Override + public Builder setStorageClass(StorageClass storageClass) { + this.storageClass = storageClass; + return this; + } + @Override Builder setMetageneration(Long metageneration) { this.metageneration = metageneration; @@ -491,6 +506,7 @@ public BlobInfo build() { updateTime = builder.updateTime; createTime = builder.createTime; isDirectory = firstNonNull(builder.isDirectory, Boolean.FALSE); + storageClass = builder.storageClass; } /** @@ -714,6 +730,13 @@ public CustomerEncryption getCustomerEncryption() { return customerEncryption; } + /** + * Returns the storage class of the blob. + */ + public StorageClass getStorageClass() { + return storageClass; + } + /** * Returns a builder for the current blob. */ @@ -771,6 +794,10 @@ public ObjectAccessControl apply(Acl acl) { if (owner != null) { storageObject.setOwner(new Owner().setEntity(owner.toPb())); } + if (storageClass != null) { + storageObject.setStorageClass(storageClass.toString()); + } + Map pbMetadata = metadata; if (metadata != null && !Data.isNull(metadata)) { pbMetadata = Maps.newHashMapWithExpectedSize(metadata.size()); @@ -909,6 +936,9 @@ public Acl apply(ObjectAccessControl objectAccessControl) { builder.setCustomerEncryption( CustomerEncryption.fromPb(storageObject.getCustomerEncryption())); } + if (storageObject.getStorageClass() != null) { + builder.setStorageClass(StorageClass.valueOf(storageObject.getStorageClass())); + } return builder.build(); } } diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java index 4c6aa4c45f41..f4ac23914d18 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java @@ -518,7 +518,7 @@ public Builder setDeleteRules(Iterable rules) { } @Override - public Builder setStorageClass(String storageClass) { + public Builder setStorageClass(StorageClass storageClass) { infoBuilder.setStorageClass(storageClass); return this; } diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java index 7a78e2b9ccb6..284a8b1c970a 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java @@ -80,7 +80,7 @@ public com.google.api.services.storage.model.Bucket apply(BucketInfo bucketInfo) private final List acl; private final List defaultAcl; private final String location; - private final String storageClass; + private final StorageClass storageClass; /** * Base class for bucket's delete rules. Allows to configure automatic deletion of blobs and blobs @@ -361,7 +361,7 @@ public abstract static class Builder { * determines the SLA and the cost of storage. A list of supported values is available * here. */ - public abstract Builder setStorageClass(String storageClass); + public abstract Builder setStorageClass(StorageClass storageClass); /** * Sets the bucket's location. Data for blobs in the bucket resides in physical storage within @@ -419,7 +419,7 @@ static final class BuilderImpl extends Builder { private String indexPage; private String notFoundPage; private List deleteRules; - private String storageClass; + private StorageClass storageClass; private String location; private String etag; private Long createTime; @@ -500,7 +500,7 @@ public Builder setDeleteRules(Iterable rules) { } @Override - public Builder setStorageClass(String storageClass) { + public Builder setStorageClass(StorageClass storageClass) { this.storageClass = storageClass; return this; } @@ -671,7 +671,7 @@ public String getLocation() { * * @see Storage Classes */ - public String getStorageClass() { + public StorageClass getStorageClass() { return storageClass; } @@ -748,7 +748,7 @@ com.google.api.services.storage.model.Bucket toPb() { bucketPb.setLocation(location); } if (storageClass != null) { - bucketPb.setStorageClass(storageClass); + bucketPb.setStorageClass(storageClass.toString()); } if (cors != null) { bucketPb.setCors(transform(cors, Cors.TO_PB_FUNCTION)); @@ -830,7 +830,7 @@ static BucketInfo fromPb(com.google.api.services.storage.model.Bucket bucketPb) builder.setLocation(bucketPb.getLocation()); } if (bucketPb.getStorageClass() != null) { - builder.setStorageClass(bucketPb.getStorageClass()); + builder.setStorageClass(StorageClass.valueOf(bucketPb.getStorageClass())); } if (bucketPb.getCors() != null) { builder.setCors(transform(bucketPb.getCors(), Cors.FROM_PB_FUNCTION)); diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java index 4ecd0ca5064e..0a3a19fc5702 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java @@ -1313,7 +1313,7 @@ public static Builder newBuilder() { * String bucketName = "my_unique_bucket"; * Bucket bucket = storage.create(BucketInfo.newBuilder(bucketName) * // See here for possible values: http://g.co/cloud/storage/docs/storage-classes - * .setStorageClass("COLDLINE") + * .setStorageClass(StorageClass.COLDLINE) * // Possible values: http://g.co/cloud/storage/docs/bucket-locations#location-mr * .setLocation("asia") * .build()); diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageClass.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageClass.java new file mode 100644 index 000000000000..bac2790f0d5b --- /dev/null +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageClass.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017 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.storage; + +/** + * Enums for the storage classes. + * See https://cloud.google.com/storage/docs/storage-classes for details. + */ +public enum StorageClass { + + /** + * Regional storage class. + */ + REGIONAL, + + /** + * Multi-regional storage class. + */ + MULTI_REGIONAL, + + /** + * Nearline storage class. + */ + NEARLINE, + + /** + * Coldline storage class. + */ + COLDLINE, + + /** + * Standard storage class. + */ + STANDARD +} diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java index a10180f5bacb..a172d946a6a7 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java @@ -66,6 +66,8 @@ public class BlobInfoTest { private static final String KEY_SHA256 = "keySha"; private static final CustomerEncryption CUSTOMER_ENCRYPTION = new CustomerEncryption(ENCRYPTION_ALGORITHM, KEY_SHA256); + private static final StorageClass STORAGE_CLASS = StorageClass.COLDLINE; + private static final BlobInfo BLOB_INFO = BlobInfo.newBuilder("b", "n", GENERATION) .setAcl(ACL) .setComponentCount(COMPONENT_COUNT) @@ -88,6 +90,7 @@ public class BlobInfoTest { .setSize(SIZE) .setUpdateTime(UPDATE_TIME) .setCreateTime(CREATE_TIME) + .setStorageClass(STORAGE_CLASS) .build(); private static final BlobInfo DIRECTORY_INFO = BlobInfo.newBuilder("b", "n/") .setSize(0L) @@ -149,6 +152,7 @@ public void testBuilder() { assertEquals(SIZE, BLOB_INFO.getSize()); assertEquals(UPDATE_TIME, BLOB_INFO.getUpdateTime()); assertEquals(CREATE_TIME, BLOB_INFO.getCreateTime()); + assertEquals(STORAGE_CLASS, BLOB_INFO.getStorageClass()); assertFalse(BLOB_INFO.isDirectory()); assertEquals("b", DIRECTORY_INFO.getBucket()); assertEquals("n/", DIRECTORY_INFO.getName()); @@ -203,6 +207,7 @@ private void compareBlobs(BlobInfo expected, BlobInfo value) { assertEquals(expected.getSelfLink(), value.getSelfLink()); assertEquals(expected.getSize(), value.getSize()); assertEquals(expected.getUpdateTime(), value.getUpdateTime()); + assertEquals(expected.getStorageClass(), value.getStorageClass()); } private void compareCustomerEncryptions(CustomerEncryption expected, CustomerEncryption value) { @@ -249,6 +254,7 @@ public void testToPbAndFromPb() { assertNull(blobInfo.getSelfLink()); assertEquals(0L, (long) blobInfo.getSize()); assertNull(blobInfo.getUpdateTime()); + assertNull(blobInfo.getStorageClass()); assertTrue(blobInfo.isDirectory()); } diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java index 67fa85aa312b..df6833010557 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java @@ -57,7 +57,7 @@ public class BucketInfoTest { private static final String INDEX_PAGE = "index.html"; private static final String NOT_FOUND_PAGE = "error.html"; private static final String LOCATION = "ASIA"; - private static final String STORAGE_CLASS = "STANDARD"; + private static final StorageClass STORAGE_CLASS = StorageClass.STANDARD; private static final Boolean VERSIONING_ENABLED = true; private static final BucketInfo BUCKET_INFO = BucketInfo.newBuilder("b") .setAcl(ACL) diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketTest.java index 39d134891f47..83ea7e3b6aa7 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketTest.java @@ -74,7 +74,7 @@ public class BucketTest { private static final String INDEX_PAGE = "index.html"; private static final String NOT_FOUND_PAGE = "error.html"; private static final String LOCATION = "ASIA"; - private static final String STORAGE_CLASS = "STANDARD"; + private static final StorageClass STORAGE_CLASS = StorageClass.STANDARD; private static final Boolean VERSIONING_ENABLED = true; private static final BucketInfo FULL_BUCKET_INFO = BucketInfo.newBuilder("b") .setAcl(ACLS) diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java index a3d754323e65..48ae816e8c3d 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java @@ -44,6 +44,7 @@ import com.google.cloud.storage.Storage.BucketField; import com.google.cloud.storage.StorageBatch; import com.google.cloud.storage.StorageBatchResult; +import com.google.cloud.storage.StorageClass; import com.google.cloud.storage.StorageException; import com.google.cloud.storage.testing.RemoteStorageHelper; import com.google.common.collect.ImmutableList; @@ -789,6 +790,29 @@ public void testCopyBlobUpdateMetadata() { assertTrue(storage.delete(BUCKET, targetBlobName)); } + @Test + public void testCopyBlobUpdateStorageClass() { + String sourceBlobName = "test-copy-blob-update-storage-class-source"; + BlobId source = BlobId.of(BUCKET, sourceBlobName); + BlobInfo sourceInfo = + BlobInfo.newBuilder(source).setStorageClass(StorageClass.STANDARD).build(); + Blob remoteSourceBlob = storage.create(sourceInfo, BLOB_BYTE_CONTENT); + assertNotNull(remoteSourceBlob); + assertEquals(StorageClass.STANDARD, remoteSourceBlob.getStorageClass()); + + String targetBlobName = "test-copy-blob-update-storage-class-target"; + BlobInfo targetInfo = BlobInfo + .newBuilder(BUCKET, targetBlobName).setStorageClass(StorageClass.COLDLINE).build(); + Storage.CopyRequest req = Storage.CopyRequest.of(source, targetInfo); + CopyWriter copyWriter = storage.copy(req); + assertEquals(BUCKET, copyWriter.getResult().getBucket()); + assertEquals(targetBlobName, copyWriter.getResult().getName()); + assertEquals(StorageClass.COLDLINE, copyWriter.getResult().getStorageClass()); + assertTrue(copyWriter.isDone()); + assertTrue(remoteSourceBlob.delete()); + assertTrue(storage.delete(BUCKET, targetBlobName)); + } + @Test public void testCopyBlobNoContentType() { String sourceBlobName = "test-copy-blob-no-content-type-source";