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/06/21 00:01:11 UTC

git commit: JCLOUDS-457: Added completeMultipartUpload and abortMultipartUplod.

Repository: jclouds-labs-aws
Updated Branches:
  refs/heads/master d0941fec0 -> 6194a3ee4


JCLOUDS-457: Added completeMultipartUpload and abortMultipartUplod.

Now the Glacier client supports completeMultipartUpload and i
abortMultipartUpload operations.


Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/commit/6194a3ee
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/tree/6194a3ee
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/diff/6194a3ee

Branch: refs/heads/master
Commit: 6194a3ee4d0c5afd21fb1174124e689bca834dab
Parents: d0941fe
Author: Roman C. Coedo <ro...@gmail.com>
Authored: Sun Jun 1 21:19:25 2014 +0200
Committer: Andrew Gaul <ga...@apache.org>
Committed: Fri Jun 20 15:00:37 2014 -0700

----------------------------------------------------------------------
 .../org/jclouds/glacier/GlacierAsyncClient.java | 27 ++++++++++++
 .../java/org/jclouds/glacier/GlacierClient.java | 31 +++++++++++++
 .../binders/BindArchiveSizeToHeaders.java       | 41 +++++++++++++++++
 .../binders/BindMultipartTreeHashToHeaders.java | 46 ++++++++++++++++++++
 .../glacier/reference/GlacierHeaders.java       |  1 +
 .../jclouds/glacier/GlacierClientMockTest.java  | 34 +++++++++++++++
 6 files changed, 180 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/blob/6194a3ee/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
----------------------------------------------------------------------
diff --git a/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java b/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
index 997fb5a..e492b7c 100644
--- a/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
+++ b/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
@@ -20,6 +20,7 @@ import static org.jclouds.blobstore.attr.BlobScopes.CONTAINER;
 
 import java.io.Closeable;
 import java.net.URI;
+import java.util.Map;
 
 import javax.inject.Named;
 import javax.ws.rs.DELETE;
@@ -31,9 +32,11 @@ import javax.ws.rs.PathParam;
 
 import org.jclouds.Fallbacks.NullOnNotFoundOr404;
 import org.jclouds.blobstore.attr.BlobScope;
+import org.jclouds.glacier.binders.BindArchiveSizeToHeaders;
 import org.jclouds.glacier.binders.BindContentRangeToHeaders;
 import org.jclouds.glacier.binders.BindDescriptionToHeaders;
 import org.jclouds.glacier.binders.BindHashesToHeaders;
+import org.jclouds.glacier.binders.BindMultipartTreeHashToHeaders;
 import org.jclouds.glacier.binders.BindPartSizeToHeaders;
 import org.jclouds.glacier.domain.PaginatedVaultCollection;
 import org.jclouds.glacier.domain.VaultMetadata;
@@ -59,6 +62,7 @@ import org.jclouds.rest.annotations.ParamValidators;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.ResponseParser;
 
+import com.google.common.hash.HashCode;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -187,4 +191,27 @@ public interface GlacierAsyncClient extends Closeable {
          @PathParam("uploadId") String uploadId,
          @BinderParam(BindContentRangeToHeaders.class) ContentRange range,
          @ParamValidators(PayloadValidator.class) @BinderParam(BindHashesToHeaders.class) Payload payload);
+
+   /**
+    * @see GlacierClient#completeMultipartUpload
+    */
+   @Named("CompleteMultipartUpload")
+   @POST
+   @Path("/-/vaults/{vault}/multipart-uploads/{uploadId}")
+   @ResponseParser(ParseArchiveIdHeader.class)
+   ListenableFuture<String> completeMultipartUpload(
+         @ParamValidators(VaultNameValidator.class) @PathParam("vault") String vaultName,
+         @PathParam("uploadId") String uploadId,
+         @BinderParam(BindMultipartTreeHashToHeaders.class) Map<Integer, HashCode> hashes,
+         @BinderParam(BindArchiveSizeToHeaders.class) long archiveSizeInMB);
+
+   /**
+    * @see GlacierClient#abortMultipartUpload
+    */
+   @Named("AbortMultipartUpload")
+   @DELETE
+   @Path("/-/vaults/{vault}/multipart-uploads/{uploadId}")
+   ListenableFuture<Boolean> abortMultipartUpload(
+         @ParamValidators(VaultNameValidator.class) @PathParam("vault") String vaultName,
+         @PathParam("uploadId") String uploadId);
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/blob/6194a3ee/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
----------------------------------------------------------------------
diff --git a/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java b/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
index 9eaa6ac..29f743d 100644
--- a/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
+++ b/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
@@ -18,6 +18,7 @@ package org.jclouds.glacier;
 
 import java.io.Closeable;
 import java.net.URI;
+import java.util.Map;
 
 import org.jclouds.glacier.domain.PaginatedVaultCollection;
 import org.jclouds.glacier.domain.VaultMetadata;
@@ -25,6 +26,8 @@ import org.jclouds.glacier.options.PaginationOptions;
 import org.jclouds.glacier.util.ContentRange;
 import org.jclouds.io.Payload;
 
+import com.google.common.hash.HashCode;
+
 /**
  * Provides access to Amazon Glacier resources via their REST API.
  * <p/>
@@ -149,4 +152,32 @@ public interface GlacierClient extends Closeable {
     * @see <a href="http://docs.aws.amazon.com/amazonglacier/latest/dev/api-upload-part.html" />
     */
    String uploadPart(String vaultName, String uploadId, ContentRange range, Payload payload);
+
+   /**
+    * Completes the multipart upload.
+    *
+    * @param vaultName
+    *           Name of the Vault where the archive is going to be stored.
+    * @param uploadId
+    *           Multipart upload identifier.
+    * @param hashes
+    *           Map containing the pairs partnumber-treehash of each uploaded part.
+    * @param archiveSizeInMB
+    *           Size of the complete archive.
+    * @return A String containing the Archive identifier in Amazon Glacier.
+    * @see <a href="http://docs.aws.amazon.com/amazonglacier/latest/dev/api-multipart-complete-upload.html" />
+    */
+   String completeMultipartUpload(String vaultName, String uploadId, Map<Integer, HashCode> hashes, long archiveSizeInMB);
+
+   /**
+    * Aborts the multipart upload.
+    *
+    * @param vaultName
+    *           Name of the Vault where the archive was going to be stored.
+    * @param uploadId
+    *           Multipart upload identifier.
+    * @return True if the multipart upload was aborted, false otherwise.
+    * @see <a href="http://docs.aws.amazon.com/amazonglacier/latest/dev/api-multipart-abort-upload.html" />
+    */
+   boolean abortMultipartUpload(String vaultName, String uploadId);
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/blob/6194a3ee/glacier/src/main/java/org/jclouds/glacier/binders/BindArchiveSizeToHeaders.java
----------------------------------------------------------------------
diff --git a/glacier/src/main/java/org/jclouds/glacier/binders/BindArchiveSizeToHeaders.java b/glacier/src/main/java/org/jclouds/glacier/binders/BindArchiveSizeToHeaders.java
new file mode 100644
index 0000000..97c500c
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/binders/BindArchiveSizeToHeaders.java
@@ -0,0 +1,41 @@
+/*
+ * 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.glacier.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.glacier.reference.GlacierHeaders;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+/**
+ * Binds the Archive size to the request headers.
+ */
+public class BindArchiveSizeToHeaders implements Binder {
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      checkArgument(checkNotNull(input, "input") instanceof Long, "This binder is only valid for long");
+      checkNotNull(request, "request");
+      Long archiveSizeInMB = Long.class.cast(input);
+      return (R) request.toBuilder()
+            .replaceHeader(GlacierHeaders.ARCHIVE_SIZE, Long.toString(archiveSizeInMB << 20))
+            .build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/blob/6194a3ee/glacier/src/main/java/org/jclouds/glacier/binders/BindMultipartTreeHashToHeaders.java
----------------------------------------------------------------------
diff --git a/glacier/src/main/java/org/jclouds/glacier/binders/BindMultipartTreeHashToHeaders.java b/glacier/src/main/java/org/jclouds/glacier/binders/BindMultipartTreeHashToHeaders.java
new file mode 100644
index 0000000..2c5f819
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/binders/BindMultipartTreeHashToHeaders.java
@@ -0,0 +1,46 @@
+/*
+ * 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.glacier.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import org.jclouds.glacier.reference.GlacierHeaders;
+import org.jclouds.glacier.util.TreeHash;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import com.google.common.hash.HashCode;
+
+/**
+ * Binds the Tree hash to the request headers.
+ */
+public class BindMultipartTreeHashToHeaders implements Binder {
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      checkArgument(checkNotNull(input, "input") instanceof Map, "This binder is only valid for Map");
+      checkNotNull(request, "request");
+      Map<Integer, HashCode> map = Map.class.cast(input);
+      checkArgument(map.size() != 0, "The map cannot be empty");
+      return (R) request.toBuilder()
+            .addHeader(GlacierHeaders.TREE_HASH, TreeHash.buildTreeHashFromMap(map).toString())
+            .build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/blob/6194a3ee/glacier/src/main/java/org/jclouds/glacier/reference/GlacierHeaders.java
----------------------------------------------------------------------
diff --git a/glacier/src/main/java/org/jclouds/glacier/reference/GlacierHeaders.java b/glacier/src/main/java/org/jclouds/glacier/reference/GlacierHeaders.java
index dbb945e..4162580 100644
--- a/glacier/src/main/java/org/jclouds/glacier/reference/GlacierHeaders.java
+++ b/glacier/src/main/java/org/jclouds/glacier/reference/GlacierHeaders.java
@@ -32,6 +32,7 @@ public final class GlacierHeaders {
    public static final String ARCHIVE_ID = HEADER_PREFIX + "archive-id";
    public static final String MULTIPART_UPLOAD_ID = HEADER_PREFIX + "multipart-upload-id";
    public static final String PART_SIZE = HEADER_PREFIX + "part-size";
+   public static final String ARCHIVE_SIZE = HEADER_PREFIX + "archive-size";
 
    private GlacierHeaders() {
    }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-aws/blob/6194a3ee/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
----------------------------------------------------------------------
diff --git a/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java b/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
index 57fca41..c1b5de5 100644
--- a/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
+++ b/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
@@ -49,7 +49,9 @@ import org.testng.annotations.AfterTest;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.hash.HashCode;
 import com.google.common.io.Resources;
 import com.google.common.net.HttpHeaders;
 import com.google.common.net.MediaType;
@@ -271,4 +273,36 @@ public class GlacierClientMockTest {
       assertEquals(request.getHeader(HttpHeaders.CONTENT_RANGE), range.buildHeader());
       assertEquals(request.getHeader(HttpHeaders.CONTENT_LENGTH), payload.getContentMetadata().getContentLength().toString());
    }
+
+   @Test
+   public void testCompleteMultipartUpload() throws IOException, InterruptedException {
+      MockResponse mr = buildBaseResponse(201);
+      mr.addHeader(HttpHeaders.LOCATION, ARCHIVE_LOCATION);
+      mr.addHeader(GlacierHeaders.ARCHIVE_ID, ARCHIVE_ID);
+      server.enqueue(mr);
+
+      HashCode partHashcode = HashCode.fromString("9bc1b2a288b26af7257a36277ae3816a7d4f16e89c1e7e77d0a5c48bad62b360");
+      ImmutableMap<Integer, HashCode> map = ImmutableMap.of(
+            1, partHashcode,
+            2, partHashcode,
+            3, partHashcode,
+            4, partHashcode);
+      assertEquals(client.completeMultipartUpload(VAULT_NAME, MULTIPART_UPLOAD_ID, map, 8L), ARCHIVE_ID);
+      RecordedRequest request = server.takeRequest();
+      assertEquals(request.getRequestLine(),
+            "POST /-/vaults/" + VAULT_NAME + "/multipart-uploads/" + MULTIPART_UPLOAD_ID + " " + HTTP);
+      assertEquals(request.getHeader(GlacierHeaders.TREE_HASH),
+            "9491cb2ed1d4e7cd53215f4017c23ec4ad21d7050a1e6bb636c4f67e8cddb844");
+      assertEquals(request.getHeader(GlacierHeaders.ARCHIVE_SIZE), "8388608");
+   }
+
+   @Test
+   public void testAbortMultipartUpload() throws IOException, InterruptedException {
+      MockResponse mr = buildBaseResponse(204);
+      server.enqueue(mr);
+
+      assertTrue(client.abortMultipartUpload(VAULT_NAME, MULTIPART_UPLOAD_ID));
+      assertEquals(server.takeRequest().getRequestLine(),
+            "DELETE /-/vaults/" + VAULT_NAME + "/multipart-uploads/" + MULTIPART_UPLOAD_ID + " " + HTTP);
+   }
 }