diff --git a/gcloud-java-examples/src/main/java/com/google/gcloud/examples/StorageExample.java b/gcloud-java-examples/src/main/java/com/google/gcloud/examples/StorageExample.java index b71a51fe6ac6..fb207023203f 100644 --- a/gcloud-java-examples/src/main/java/com/google/gcloud/examples/StorageExample.java +++ b/gcloud-java-examples/src/main/java/com/google/gcloud/examples/StorageExample.java @@ -376,7 +376,7 @@ CopyRequest parse(String... args) { if (args.length != 4) { throw new IllegalArgumentException(); } - return CopyRequest.of(args[0], args[1], BlobInfo.builder(args[2], args[3]).build()); + return CopyRequest.of(args[0], args[1], BlobId.of(args[2], args[3])); } @Override @@ -544,11 +544,14 @@ public static void main(String... args) throws Exception { StorageOptions.Builder optionsBuilder = StorageOptions.builder().retryParams(RetryParams.getDefaultInstance()); StorageAction action; + String actionName; if (args.length >= 2 && !ACTIONS.containsKey(args[0])) { + actionName = args[1]; optionsBuilder.projectId(args[0]); action = ACTIONS.get(args[1]); args = Arrays.copyOfRange(args, 2, args.length); } else { + actionName = args[0]; action = ACTIONS.get(args[0]); args = Arrays.copyOfRange(args, 1, args.length); } @@ -562,7 +565,7 @@ public static void main(String... args) throws Exception { try { request = action.parse(args); } catch (IllegalArgumentException ex) { - System.out.println("Invalid input for action '" + args[1] + "'"); + System.out.println("Invalid input for action '" + actionName + "'"); System.out.println("Expected: " + action.params()); return; } catch (Exception ex) { diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java index 284a7818457c..8f988922aad9 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java @@ -223,9 +223,8 @@ public Blob update(BlobInfo blobInfo, BlobTargetOption... options) { * @throws StorageException upon failure */ public CopyWriter copyTo(BlobId targetBlob, BlobSourceOption... options) { - BlobInfo updatedInfo = BlobInfo.builder(targetBlob).build(); CopyRequest copyRequest = CopyRequest.builder().source(info.bucket(), info.name()) - .sourceOptions(convert(info, options)).target(updatedInfo).build(); + .sourceOptions(convert(info, options)).target(targetBlob).build(); return storage.copy(copyRequest); } @@ -266,10 +265,7 @@ public CopyWriter copyTo(String targetBucket, BlobSourceOption... options) { * @throws StorageException upon failure */ public CopyWriter copyTo(String targetBucket, String targetBlob, BlobSourceOption... options) { - BlobInfo updatedInfo = BlobInfo.builder(targetBucket, targetBlob).build(); - CopyRequest copyRequest = CopyRequest.builder().source(info.bucket(), info.name()) - .sourceOptions(convert(info, options)).target(updatedInfo).build(); - return storage.copy(copyRequest); + return copyTo(BlobId.of(targetBucket, targetBlob), options); } /** diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java index 98698107a205..9bc971a09dba 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java @@ -551,31 +551,43 @@ public Builder sourceOptions(Iterable options) { } /** - * Sets the copy target. + * Sets the copy target. Target blob information is copied from source. * * @return the builder. */ - public Builder target(BlobInfo target) { - this.target = target; + public Builder target(BlobId target) { + this.target = BlobInfo.builder(target).build(); return this; } /** - * Sets blob's target options. + * Sets the copy target and target options. {@code target} parameter is used to override + * source blob information (e.g. {@code contentType}, {@code contentLanguage}). {@code + * target.contentType} is a required field. * * @return the builder. + * @throws IllegalArgumentException if {@code target.contentType} is {@code null} */ - public Builder targetOptions(BlobTargetOption... options) { + public Builder target(BlobInfo target, BlobTargetOption... options) + throws IllegalArgumentException { + checkContentType(target); + this.target = target; Collections.addAll(targetOptions, options); return this; } /** - * Sets blob's target options. + * Sets the copy target and target options. {@code target} parameter is used to override + * source blob information (e.g. {@code contentType}, {@code contentLanguage}). {@code + * target.contentType} is a required field. * * @return the builder. + * @throws IllegalArgumentException if {@code target.contentType} is {@code null} */ - public Builder targetOptions(Iterable options) { + public Builder target(BlobInfo target, Iterable options) + throws IllegalArgumentException { + checkContentType(target); + this.target = target; Iterables.addAll(targetOptions, options); return this; } @@ -647,27 +659,101 @@ public Long megabytesCopiedPerChunk() { return megabytesCopiedPerChunk; } - public static CopyRequest of(String sourceBucket, String sourceBlob, BlobInfo target) { + /** + * Creates a copy request. {@code target} parameter is used to override source blob information + * (e.g. {@code contentType}, {@code contentLanguage}). {@code target.contentType} is a required + * field. + * + * @param sourceBucket name of the bucket containing the source blob + * @param sourceBlob name of the source blob + * @param target a {@code BlobInfo} object for the target blob + * @return a copy request. + * @throws IllegalArgumentException if {@code target.contentType} is {@code null} + */ + public static CopyRequest of(String sourceBucket, String sourceBlob, BlobInfo target) + throws IllegalArgumentException { + checkContentType(target); return builder().source(sourceBucket, sourceBlob).target(target).build(); } - public static CopyRequest of(BlobId sourceBlobId, BlobInfo target) { + /** + * Creates a copy request. {@code target} parameter is used to override source blob information + * (e.g. {@code contentType}, {@code contentLanguage}). {@code target.contentType} is a required + * field. + * + * @param sourceBlobId a {@code BlobId} object for the source blob + * @param target a {@code BlobInfo} object for the target blob + * @return a copy request. + * @throws IllegalArgumentException if {@code target.contentType} is {@code null} + */ + public static CopyRequest of(BlobId sourceBlobId, BlobInfo target) + throws IllegalArgumentException { + checkContentType(target); return builder().source(sourceBlobId).target(target).build(); } + /** + * Creates a copy request. Target blob information is copied from source. + * + * @param sourceBucket name of the bucket containing both the source and the target blob + * @param sourceBlob name of the source blob + * @param targetBlob name of the target blob + * @return a copy request. + */ public static CopyRequest of(String sourceBucket, String sourceBlob, String targetBlob) { - return of(sourceBucket, sourceBlob, - BlobInfo.builder(BlobId.of(sourceBucket, targetBlob)).build()); + return CopyRequest.builder() + .source(sourceBucket, sourceBlob) + .target(BlobId.of(sourceBucket, targetBlob)) + .build(); } + /** + * Creates a copy request. Target blob information is copied from source. + * + * @param sourceBucket name of the bucket containing the source blob + * @param sourceBlob name of the source blob + * @param target a {@code BlobId} object for the target blob + * @return a copy request. + */ + public static CopyRequest of(String sourceBucket, String sourceBlob, BlobId target) { + return builder().source(sourceBucket, sourceBlob).target(target).build(); + } + + /** + * Creates a copy request. Target blob information is copied from source. + * + * @param sourceBlobId a {@code BlobId} object for the source blob + * @param targetBlob name of the target blob, in the same bucket of the source blob + * @return a copy request. + */ public static CopyRequest of(BlobId sourceBlobId, String targetBlob) { - return of(sourceBlobId, - BlobInfo.builder(BlobId.of(sourceBlobId.bucket(), targetBlob)).build()); + return CopyRequest.builder() + .source(sourceBlobId) + .target(BlobId.of(sourceBlobId.bucket(), targetBlob)) + .build(); + } + + /** + * Creates a copy request. Target blob information is copied from source. + * + * @param sourceBlobId a {@code BlobId} object for the source blob + * @param targetBlobId a {@code BlobId} object for the target blob + * @return a copy request. + */ + public static CopyRequest of(BlobId sourceBlobId, BlobId targetBlobId) { + return CopyRequest.builder() + .source(sourceBlobId) + .target(targetBlobId) + .build(); } public static Builder builder() { return new Builder(); } + + private static void checkContentType(BlobInfo blobInfo) throws IllegalArgumentException { + checkArgument(blobInfo.contentType() != null, "Blob content type can not be null"); + } } /** diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/CopyRequestTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/CopyRequestTest.java new file mode 100644 index 000000000000..b7e8d14e53a1 --- /dev/null +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/CopyRequestTest.java @@ -0,0 +1,129 @@ +/* + * Copyright 2015 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.gcloud.storage; + +import static com.google.gcloud.storage.Storage.PredefinedAcl.PUBLIC_READ; +import static org.junit.Assert.assertEquals; + +import com.google.common.collect.ImmutableList; +import com.google.gcloud.storage.Storage.BlobSourceOption; +import com.google.gcloud.storage.Storage.BlobTargetOption; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class CopyRequestTest { + + private static final String SOURCE_BUCKET_NAME = "b0"; + private static final String SOURCE_BLOB_NAME = "o0"; + private static final String TARGET_BUCKET_NAME = "b1"; + private static final String TARGET_BLOB_NAME = "o1"; + private static final String TARGET_BLOB_CONTENT_TYPE = "contentType"; + private static final BlobId SOURCE_BLOB_ID = BlobId.of(SOURCE_BUCKET_NAME, SOURCE_BLOB_NAME); + private static final BlobId TARGET_BLOB_ID = BlobId.of(TARGET_BUCKET_NAME, TARGET_BLOB_NAME); + private static final BlobInfo TARGET_BLOB_INFO = BlobInfo.builder(TARGET_BLOB_ID) + .contentType(TARGET_BLOB_CONTENT_TYPE).build(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testCopyRequest() { + Storage.CopyRequest copyRequest1 = Storage.CopyRequest.builder() + .source(SOURCE_BLOB_ID) + .sourceOptions(BlobSourceOption.generationMatch(1)) + .target(TARGET_BLOB_INFO, BlobTargetOption.predefinedAcl(PUBLIC_READ)) + .build(); + assertEquals(SOURCE_BLOB_ID, copyRequest1.source()); + assertEquals(1, copyRequest1.sourceOptions().size()); + assertEquals(BlobSourceOption.generationMatch(1), copyRequest1.sourceOptions().get(0)); + assertEquals(TARGET_BLOB_INFO, copyRequest1.target()); + assertEquals(1, copyRequest1.targetOptions().size()); + assertEquals(BlobTargetOption.predefinedAcl(PUBLIC_READ), copyRequest1.targetOptions().get(0)); + + Storage.CopyRequest copyRequest2 = Storage.CopyRequest.builder() + .source(SOURCE_BUCKET_NAME, SOURCE_BLOB_NAME) + .target(TARGET_BLOB_ID) + .build(); + assertEquals(SOURCE_BLOB_ID, copyRequest2.source()); + assertEquals(BlobInfo.builder(TARGET_BLOB_ID).build(), copyRequest2.target()); + + Storage.CopyRequest copyRequest3 = Storage.CopyRequest.builder() + .source(SOURCE_BLOB_ID) + .target(TARGET_BLOB_INFO, ImmutableList.of(BlobTargetOption.predefinedAcl(PUBLIC_READ))) + .build(); + assertEquals(SOURCE_BLOB_ID, copyRequest3.source()); + assertEquals(TARGET_BLOB_INFO, copyRequest3.target()); + assertEquals(ImmutableList.of(BlobTargetOption.predefinedAcl(PUBLIC_READ)), + copyRequest3.targetOptions()); + } + + @Test + public void testCopyRequestOf() { + Storage.CopyRequest copyRequest1 = Storage.CopyRequest.of(SOURCE_BLOB_ID, TARGET_BLOB_INFO); + assertEquals(SOURCE_BLOB_ID, copyRequest1.source()); + assertEquals(TARGET_BLOB_INFO, copyRequest1.target()); + + Storage.CopyRequest copyRequest2 = Storage.CopyRequest.of(SOURCE_BLOB_ID, TARGET_BLOB_NAME); + assertEquals(SOURCE_BLOB_ID, copyRequest2.source()); + assertEquals(BlobInfo.builder(SOURCE_BUCKET_NAME, TARGET_BLOB_NAME).build(), + copyRequest2.target()); + + Storage.CopyRequest copyRequest3 = + Storage.CopyRequest.of(SOURCE_BUCKET_NAME, SOURCE_BLOB_NAME, TARGET_BLOB_INFO); + assertEquals(SOURCE_BLOB_ID, copyRequest3.source()); + assertEquals(TARGET_BLOB_INFO, copyRequest3.target()); + + Storage.CopyRequest copyRequest4 = + Storage.CopyRequest.of(SOURCE_BUCKET_NAME, SOURCE_BLOB_NAME, TARGET_BLOB_NAME); + assertEquals(SOURCE_BLOB_ID, copyRequest4.source()); + assertEquals(BlobInfo.builder(SOURCE_BUCKET_NAME, TARGET_BLOB_NAME).build(), + copyRequest4.target()); + + Storage.CopyRequest copyRequest5 = Storage.CopyRequest.of(SOURCE_BLOB_ID, TARGET_BLOB_ID); + assertEquals(SOURCE_BLOB_ID, copyRequest5.source()); + assertEquals(BlobInfo.builder(TARGET_BLOB_ID).build(), copyRequest5.target()); + + Storage.CopyRequest copyRequest6 = + Storage.CopyRequest.of(SOURCE_BUCKET_NAME, SOURCE_BLOB_NAME, TARGET_BLOB_ID); + assertEquals(SOURCE_BLOB_ID, copyRequest6.source()); + assertEquals(BlobInfo.builder(TARGET_BLOB_ID).build(), copyRequest6.target()); + } + + @Test + public void testCopyRequestFail() { + thrown.expect(IllegalArgumentException.class); + Storage.CopyRequest.builder() + .source(SOURCE_BLOB_ID) + .target(BlobInfo.builder(TARGET_BLOB_ID).build()) + .build(); + } + + @Test + public void testCopyRequestOfBlobInfoFail() { + thrown.expect(IllegalArgumentException.class); + Storage.CopyRequest.of(SOURCE_BLOB_ID, BlobInfo.builder(TARGET_BLOB_ID).build()); + } + + @Test + public void testCopyRequestOfStringFail() { + thrown.expect(IllegalArgumentException.class); + Storage.CopyRequest.of( + SOURCE_BUCKET_NAME, SOURCE_BLOB_NAME, BlobInfo.builder(TARGET_BLOB_ID).build()); + } +} diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java index 8957ed2b8364..3aad7b712e48 100644 --- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java @@ -325,8 +325,7 @@ public void testCopyBlob() { .build(); assertNotNull(storage.create(blob, BLOB_BYTE_CONTENT)); String targetBlobName = "test-copy-blob-target"; - BlobInfo target = BlobInfo.builder(BUCKET, targetBlobName).build(); - Storage.CopyRequest req = Storage.CopyRequest.of(source, target); + Storage.CopyRequest req = Storage.CopyRequest.of(source, BlobId.of(BUCKET, targetBlobName)); CopyWriter copyWriter = storage.copy(req); assertEquals(BUCKET, copyWriter.result().bucket()); assertEquals(targetBlobName, copyWriter.result().name()); diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java index 910d614c64d7..bdac54bcef2d 100644 --- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java @@ -591,7 +591,7 @@ public void testComposeWithOptions() { @Test public void testCopy() { - CopyRequest request = Storage.CopyRequest.of(BLOB_INFO1.blobId(), BLOB_INFO2); + CopyRequest request = Storage.CopyRequest.of(BLOB_INFO1.blobId(), BLOB_INFO2.blobId()); StorageRpc.RewriteRequest rpcRequest = new StorageRpc.RewriteRequest(request.source().toPb(), EMPTY_RPC_OPTIONS, request.target().toPb(), EMPTY_RPC_OPTIONS, null); StorageRpc.RewriteResponse rpcResponse = new StorageRpc.RewriteResponse(rpcRequest, null, 42L, @@ -610,8 +610,7 @@ public void testCopyWithOptions() { CopyRequest request = Storage.CopyRequest.builder() .source(BLOB_INFO2.blobId()) .sourceOptions(BLOB_SOURCE_GENERATION, BLOB_SOURCE_METAGENERATION) - .target(BLOB_INFO1) - .targetOptions(BLOB_TARGET_GENERATION, BLOB_TARGET_METAGENERATION) + .target(BLOB_INFO1, BLOB_TARGET_GENERATION, BLOB_TARGET_METAGENERATION) .build(); StorageRpc.RewriteRequest rpcRequest = new StorageRpc.RewriteRequest(request.source().toPb(), BLOB_SOURCE_OPTIONS_COPY, request.target().toPb(), BLOB_TARGET_OPTIONS_COMPOSE, null); @@ -628,7 +627,7 @@ public void testCopyWithOptions() { @Test public void testCopyMultipleRequests() { - CopyRequest request = Storage.CopyRequest.of(BLOB_INFO1.blobId(), BLOB_INFO2); + CopyRequest request = Storage.CopyRequest.of(BLOB_INFO1.blobId(), BLOB_INFO2.blobId()); StorageRpc.RewriteRequest rpcRequest = new StorageRpc.RewriteRequest(request.source().toPb(), EMPTY_RPC_OPTIONS, request.target().toPb(), EMPTY_RPC_OPTIONS, null); StorageRpc.RewriteResponse rpcResponse1 = new StorageRpc.RewriteResponse(rpcRequest, null, 42L,