mirror of https://github.com/apache/jclouds.git
JCLOUDS-457: Added completeMultipartUpload and abortMultipartUplod.
Now the Glacier client supports completeMultipartUpload and i abortMultipartUpload operations.
This commit is contained in:
parent
76ea768cb8
commit
b0dddca449
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue