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")