You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ga...@apache.org on 2014/08/29 20:00:49 UTC
git commit: JCLOUDS-458: Multipart Related Upload
Repository: jclouds-labs-google
Updated Branches:
refs/heads/master 155fc1124 -> 626a03a03
JCLOUDS-458: Multipart Related Upload
Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/commit/626a03a0
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/tree/626a03a0
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/diff/626a03a0
Branch: refs/heads/master
Commit: 626a03a03ccfbe166fae7e1f14da53a2a49e483f
Parents: 155fc11
Author: hsbhathiya <hs...@gmail.com>
Authored: Fri Aug 29 01:45:03 2014 +0530
Committer: Andrew Gaul <ga...@apache.org>
Committed: Fri Aug 29 10:58:41 2014 -0700
----------------------------------------------------------------------
google-cloud-storage/pom.xml | 6 ++
.../binders/MultipartUploadBinder.java | 71 ++++++++++++++++++++
.../googlecloudstorage/features/ObjectApi.java | 24 +++++++
.../features/ObjectApiLiveTest.java | 47 ++++++++++++-
4 files changed, 147 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/626a03a0/google-cloud-storage/pom.xml
----------------------------------------------------------------------
diff --git a/google-cloud-storage/pom.xml b/google-cloud-storage/pom.xml
index 3289de9..84351be 100644
--- a/google-cloud-storage/pom.xml
+++ b/google-cloud-storage/pom.xml
@@ -90,6 +90,12 @@
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>1.6.1</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<profiles>
<profile>
http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/626a03a0/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/binders/MultipartUploadBinder.java
----------------------------------------------------------------------
diff --git a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/binders/MultipartUploadBinder.java b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/binders/MultipartUploadBinder.java
new file mode 100644
index 0000000..b286d28
--- /dev/null
+++ b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/binders/MultipartUploadBinder.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.jclouds.googlecloudstorage.binders;
+
+import java.util.Map;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.googlecloudstorage.domain.templates.ObjectTemplate;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.jclouds.io.payloads.MultipartForm;
+import org.jclouds.io.payloads.Part;
+import org.jclouds.io.payloads.StringPayload;
+import org.jclouds.rest.MapBinder;
+
+import com.google.gson.Gson;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class MultipartUploadBinder implements MapBinder {
+
+ private final String BOUNDARY_HEADER = "multipart_boundary";
+
+ @Override
+ public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams)
+ throws IllegalArgumentException {
+
+ ObjectTemplate template = (ObjectTemplate) postParams.get("template");
+ Payload payload = (Payload) postParams.get("payload");
+
+ String contentType = checkNotNull(template.getContentType(), "contentType");
+ Long length = checkNotNull(template.getSize(), "contetLength");
+
+ StringPayload jsonPayload = Payloads.newStringPayload(new Gson().toJson(template));
+
+ payload.getContentMetadata().setContentLength(length);
+
+ Part jsonPart = Part.create("Metadata", jsonPayload,
+ new Part.PartOptions().contentType(MediaType.APPLICATION_JSON));
+ Part mediaPart = Part.create(template.getName(), payload, new Part.PartOptions().contentType(contentType));
+
+ MultipartForm compPayload = new MultipartForm(BOUNDARY_HEADER, jsonPart, mediaPart);
+ request.setPayload(compPayload);
+ // HeaderPart
+ request.toBuilder().replaceHeader(HttpHeaders.CONTENT_TYPE, "Multipart/related; boundary= " + BOUNDARY_HEADER)
+ .build();
+ return request;
+ }
+
+ @Override
+ public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+ return request;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/626a03a0/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java
----------------------------------------------------------------------
diff --git a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java
index a04d9ba..11299c1 100644
--- a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java
+++ b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java
@@ -35,6 +35,7 @@ import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.Fallbacks.TrueOnNotFoundOr404;
import org.jclouds.googlecloudstorage.binders.ComposeObjectBinder;
+import org.jclouds.googlecloudstorage.binders.MultipartUploadBinder;
import org.jclouds.googlecloudstorage.binders.UploadBinder;
import org.jclouds.googlecloudstorage.domain.GCSObject;
import org.jclouds.googlecloudstorage.domain.ListPage;
@@ -459,4 +460,27 @@ public interface ObjectApi {
@PathParam("destinationObject") String destinationObject, @PathParam("sourceBucket") String sourceBucket,
@PathParam("sourceObject") String sourceObject, CopyObjectOptions options);
+ /**
+ * Stores a new object with metadata.
+ *
+ * @see https://developers.google.com/storage/docs/json_api/v1/how-tos/upload#multipart
+ *
+ * @param bucketName
+ * Name of the bucket in which the object to be stored
+ * @param objectTemplate
+ * Supply an {@link ObjectTemplate}.
+ *
+ * @return a {@link GCSObject}
+ */
+
+ @Named("Object:multipartUpload")
+ @POST
+ @QueryParams(keys = "uploadType", values = "multipart")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Path("/upload/storage/v1/b/{bucket}/o")
+ @OAuthScopes(STORAGE_FULLCONTROL_SCOPE)
+ @MapBinder(MultipartUploadBinder.class)
+ GCSObject multipartUpload(@PathParam("bucket") String bucketName,
+ @PayloadParam("template") ObjectTemplate objectTemplate, @PayloadParam("payload") Payload payload);
+
}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/626a03a0/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiLiveTest.java b/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiLiveTest.java
index 854a64f..a454c48 100644
--- a/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiLiveTest.java
+++ b/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiLiveTest.java
@@ -18,6 +18,8 @@ package org.jclouds.googlecloudstorage.features;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
import java.io.IOException;
import java.util.Set;
@@ -55,6 +57,7 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.beust.jcommander.internal.Sets;
+import com.google.common.collect.ImmutableMap;
import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
@@ -66,6 +69,7 @@ public class ObjectApiLiveTest extends BaseGoogleCloudStorageApiLiveTest {
private static final String BUCKET_NAME2 = "jcloudobjectdestination" + UUID.randomUUID();
private static final String UPLOAD_OBJECT_NAME = "objectOperation.txt";
private static final String UPLOAD_OBJECT_NAME2 = "jcloudslogo.jpg";
+ private static final String MULTIPART_UPLOAD_OBJECT = "multipart_related.jpg";
private static final String COPIED_OBJECT_NAME = "copyofObjectOperation.txt";
private static final String COMPOSED_OBJECT = "ComposedObject1.txt";
private static final String COMPOSED_OBJECT2 = "ComposedObject2.json";
@@ -196,7 +200,7 @@ public class ObjectApiLiveTest extends BaseGoogleCloudStorageApiLiveTest {
assertEquals(gcsObject.getName(), COPIED_OBJECT_NAME);
assertEquals(gcsObject.getContentType(), "text/plain");
- //Test for data
+ // Test for data
PayloadEnclosingImpl impl = api().download(BUCKET_NAME2, COPIED_OBJECT_NAME);
assertNotNull(impl);
@@ -365,12 +369,53 @@ public class ObjectApiLiveTest extends BaseGoogleCloudStorageApiLiveTest {
}
@Test(groups = "live", dependsOnMethods = "testPatchObjectsWithOptions")
+ public void testMultipartJpegUpload() throws IOException {
+ long contentLength = 32 * 1024L;
+ ByteSource byteSource = TestUtils.randomByteSource().slice(0, contentLength);
+ ByteSourcePayload payload = Payloads.newByteSourcePayload(byteSource);
+ PayloadEnclosingImpl payloadImpl = new PayloadEnclosingImpl(payload);
+
+ ObjectTemplate template = new ObjectTemplate();
+
+ ObjectAccessControls oacl = ObjectAccessControls.builder().bucket(BUCKET_NAME).entity("allUsers")
+ .role(ObjectRole.OWNER).build();
+
+ // This would trigger server side validation of md5
+ hcMd5 = byteSource.hash(Hashing.md5());
+
+ // This would trigger server side validation of crc32c
+ hcCrc32c = byteSource.hash(Hashing.crc32c());
+
+ template.contentType("image/jpeg").addAcl(oacl).size(contentLength).name(MULTIPART_UPLOAD_OBJECT)
+ .contentLanguage("en").contentDisposition("attachment").md5Hash(hcMd5)
+ .customMetadata("custommetakey1", "custommetavalue1").crc32c(hcCrc32c)
+ .customMetadata(ImmutableMap.of("Adrian", "powderpuff"));
+
+ GCSObject gcsObject = api().multipartUpload(BUCKET_NAME, template, payloadImpl.getPayload());
+
+ assertThat(gcsObject.getBucket()).isEqualTo(BUCKET_NAME);
+ assertThat(gcsObject.getName()).isEqualTo(MULTIPART_UPLOAD_OBJECT);
+ assertThat(gcsObject.getMd5HashCode()).isEqualTo(hcMd5);
+ assertThat(gcsObject.getCrc32cHashcode()).isEqualTo(hcCrc32c);
+
+ assertThat(gcsObject.getAllMetadata()).contains(entry("custommetakey1", "custommetavalue1"),
+ entry("Adrian", "powderpuff")).doesNotContainKey("adrian");
+
+ PayloadEnclosingImpl impl = api().download(BUCKET_NAME, MULTIPART_UPLOAD_OBJECT);
+
+ assertThat(ByteStreams2.toByteArrayAndClose(impl.getPayload().openStream())).isEqualTo(
+ ByteStreams2.toByteArrayAndClose(payloadImpl.getPayload().openStream()));
+ }
+
+ @Test(groups = "live", dependsOnMethods = "testMultipartJpegUpload")
public void testDeleteObject() {
api().deleteObject(BUCKET_NAME2, UPLOAD_OBJECT_NAME);
api().deleteObject(BUCKET_NAME2, COMPOSED_OBJECT2);
api().deleteObject(BUCKET_NAME2, COMPOSED_OBJECT);
api().deleteObject(BUCKET_NAME2, COPIED_OBJECT_NAME);
+ api().deleteObject(BUCKET_NAME, UPLOAD_OBJECT_NAME);
api().deleteObject(BUCKET_NAME, UPLOAD_OBJECT_NAME2);
+ api().deleteObject(BUCKET_NAME, MULTIPART_UPLOAD_OBJECT);
}
@Test(groups = "live", dependsOnMethods = "testPatchObjectsWithOptions")