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 2016/06/13 23:28:25 UTC
[2/3] jclouds git commit: JCLOUDS-1125: S3 list multipart uploads
JCLOUDS-1125: S3 list multipart uploads
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/445664c9
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/445664c9
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/445664c9
Branch: refs/heads/master
Commit: 445664c9f1da25ddd8e0b85ad089583fd7d189ac
Parents: 61ab28c
Author: Andrew Gaul <ga...@apache.org>
Authored: Thu Jun 9 17:23:38 2016 -0700
Committer: Andrew Gaul <ga...@apache.org>
Committed: Mon Jun 13 16:26:43 2016 -0700
----------------------------------------------------------------------
apis/s3/pom.xml | 5 +
.../src/main/java/org/jclouds/s3/S3Client.java | 13 ++
.../s3/domain/ListMultipartUploadsResponse.java | 57 ++++++++
.../s3/xml/ListMultipartUploadsHandler.java | 129 +++++++++++++++++++
.../java/org/jclouds/s3/S3ClientLiveTest.java | 30 +++++
.../test/java/org/jclouds/s3/S3ClientTest.java | 18 +++
6 files changed, 252 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jclouds/blob/445664c9/apis/s3/pom.xml
----------------------------------------------------------------------
diff --git a/apis/s3/pom.xml b/apis/s3/pom.xml
index f0fc2a5..8f4c738 100644
--- a/apis/s3/pom.xml
+++ b/apis/s3/pom.xml
@@ -100,6 +100,11 @@
<artifactId>auto-service</artifactId>
<optional>true</optional>
</dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<profiles>
http://git-wip-us.apache.org/repos/asf/jclouds/blob/445664c9/apis/s3/src/main/java/org/jclouds/s3/S3Client.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/main/java/org/jclouds/s3/S3Client.java b/apis/s3/src/main/java/org/jclouds/s3/S3Client.java
index fe3caea..cb1d9bd 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/S3Client.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/S3Client.java
@@ -75,6 +75,7 @@ import org.jclouds.s3.domain.BucketMetadata;
import org.jclouds.s3.domain.CannedAccessPolicy;
import org.jclouds.s3.domain.DeleteResult;
import org.jclouds.s3.domain.ListBucketResponse;
+import org.jclouds.s3.domain.ListMultipartUploadsResponse;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.Payer;
import org.jclouds.s3.domain.S3Object;
@@ -100,6 +101,7 @@ import org.jclouds.s3.xml.CopyObjectHandler;
import org.jclouds.s3.xml.DeleteResultHandler;
import org.jclouds.s3.xml.ListAllMyBucketsHandler;
import org.jclouds.s3.xml.ListBucketHandler;
+import org.jclouds.s3.xml.ListMultipartUploadsHandler;
import org.jclouds.s3.xml.LocationConstraintHandler;
import org.jclouds.s3.xml.PartIdsFromHttpResponse;
import org.jclouds.s3.xml.PayerHandler;
@@ -785,4 +787,15 @@ public interface S3Client extends Closeable {
Map<Integer, String> listMultipartParts(@Bucket @EndpointParam(parser = AssignCorrectHostnameForBucket.class)
@BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators(BucketNameValidator.class) String bucketName,
@PathParam("key") String key, @QueryParam("uploadId") String uploadId);
+
+ @Named("ListMultipartUploads")
+ @GET
+ @Path("/")
+ @QueryParams(keys = "uploads")
+ @XMLResponseParser(ListMultipartUploadsHandler.class)
+ ListMultipartUploadsResponse listMultipartUploads(@Bucket @EndpointParam(parser = AssignCorrectHostnameForBucket.class)
+ @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators(BucketNameValidator.class) String bucketName,
+ @QueryParam("delimiter") @Nullable String delimiter, @QueryParam("max-uploads") @Nullable Integer maxUploads,
+ @QueryParam("key-marker") @Nullable String keyMarker, @QueryParam("prefix") @Nullable String prefix,
+ @QueryParam("upload-id-marker") @Nullable String uploadIdMarker);
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/445664c9/apis/s3/src/main/java/org/jclouds/s3/domain/ListMultipartUploadsResponse.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/main/java/org/jclouds/s3/domain/ListMultipartUploadsResponse.java b/apis/s3/src/main/java/org/jclouds/s3/domain/ListMultipartUploadsResponse.java
new file mode 100644
index 0000000..16ebaa8
--- /dev/null
+++ b/apis/s3/src/main/java/org/jclouds/s3/domain/ListMultipartUploadsResponse.java
@@ -0,0 +1,57 @@
+/*
+ * 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.s3.domain;
+
+import java.util.Date;
+import java.util.List;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+
+@AutoValue
+public abstract class ListMultipartUploadsResponse {
+ public abstract String bucket();
+ @Nullable public abstract String keyMarker();
+ @Nullable public abstract String uploadIdMarker();
+ @Nullable public abstract String nextKeyMarker();
+ @Nullable public abstract String nextUploadIdMarker();
+ public abstract int maxUploads();
+ public abstract boolean isTruncated();
+ public abstract List<Upload> uploads();
+
+ public static ListMultipartUploadsResponse create(String bucket, @Nullable String keyMarker, @Nullable String uploadIdMarker, @Nullable String nextKeyMarker, @Nullable String nextUploadIdMarker, int maxUploads, boolean isTruncated, List<Upload> uploads) {
+ uploads = ImmutableList.copyOf(uploads);
+ return new AutoValue_ListMultipartUploadsResponse(bucket, keyMarker, uploadIdMarker, nextKeyMarker, nextUploadIdMarker, maxUploads, isTruncated, uploads);
+ }
+
+ @AutoValue
+ public abstract static class Upload {
+ public abstract String key();
+ public abstract String uploadId();
+ public abstract CanonicalUser initiator();
+ public abstract CanonicalUser owner();
+ public abstract ObjectMetadata.StorageClass storageClass();
+ public abstract Date initiated();
+
+ public static Upload create(String key, String uploadId, CanonicalUser initiator, CanonicalUser owner, ObjectMetadata.StorageClass storageClass, Date initiated) {
+ initiated = (Date) initiated.clone();
+ return new AutoValue_ListMultipartUploadsResponse_Upload(key, uploadId, initiator, owner, storageClass, initiated);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/445664c9/apis/s3/src/main/java/org/jclouds/s3/xml/ListMultipartUploadsHandler.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/main/java/org/jclouds/s3/xml/ListMultipartUploadsHandler.java b/apis/s3/src/main/java/org/jclouds/s3/xml/ListMultipartUploadsHandler.java
new file mode 100644
index 0000000..fc855d3
--- /dev/null
+++ b/apis/s3/src/main/java/org/jclouds/s3/xml/ListMultipartUploadsHandler.java
@@ -0,0 +1,129 @@
+/*
+ * 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.s3.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+import java.util.Date;
+
+import javax.inject.Inject;
+
+import org.jclouds.date.DateService;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.s3.domain.CanonicalUser;
+import org.jclouds.s3.domain.ListMultipartUploadsResponse;
+import org.jclouds.s3.domain.ObjectMetadata;
+import org.xml.sax.Attributes;
+
+import com.google.common.collect.ImmutableList;
+
+public final class ListMultipartUploadsHandler extends ParseSax.HandlerWithResult<ListMultipartUploadsResponse> {
+ private String bucket;
+ private String keyMarker;
+ private String uploadIdMarker;
+ private String nextKeyMarker;
+ private String nextUploadIdMarker;
+ private int maxUploads;
+ private boolean isTruncated;
+ private final ImmutableList.Builder<ListMultipartUploadsResponse.Upload> uploads = ImmutableList.builder();
+
+ private String key;
+ private String uploadId;
+ private String id;
+ private String displayName;
+ private CanonicalUser initiator;
+ private CanonicalUser owner;
+ private ObjectMetadata.StorageClass storageClass;
+ private Date initiated;
+
+ private final DateService dateParser;
+ private final StringBuilder currentText = new StringBuilder();
+ private boolean inUpload;
+ private boolean inInitiator;
+ private boolean inOwner;
+
+ @Inject
+ public ListMultipartUploadsHandler(DateService dateParser) {
+ this.dateParser = dateParser;
+ }
+
+ public ListMultipartUploadsResponse getResult() {
+ return ListMultipartUploadsResponse.create(bucket, keyMarker, uploadIdMarker, nextKeyMarker, nextUploadIdMarker, maxUploads, isTruncated, uploads.build());
+ }
+
+ public void startElement(String uri, String name, String qName, Attributes attrs) {
+ if (qName.equals("Upload")) {
+ inUpload = true;
+ } else if (qName.equals("Initiator")) {
+ inInitiator = true;
+ } else if (qName.equals("Owner")) {
+ inOwner = true;
+ }
+ currentText.setLength(0);
+ }
+
+ public void endElement(String uri, String name, String qName) {
+ if (qName.equals("Bucket")) {
+ bucket = currentOrNull(currentText);
+ } else if (qName.equals("KeyMarker")) {
+ keyMarker = currentOrNull(currentText);
+ } else if (qName.equals("UploadIdMarker")) {
+ uploadIdMarker = currentOrNull(currentText);
+ } else if (qName.equals("NextKeyMarker")) {
+ nextKeyMarker = currentOrNull(currentText);
+ } else if (qName.equals("NextUploadIdMarker")) {
+ nextUploadIdMarker = currentOrNull(currentText);
+ } else if (qName.equals("MaxUploads")) {
+ maxUploads = Integer.parseInt(currentOrNull(currentText));
+ } else if (qName.equals("IsTruncated")) {
+ isTruncated = Boolean.parseBoolean(currentOrNull(currentText));
+ } else if (qName.equals("Key")) {
+ key = currentOrNull(currentText);
+ } else if (qName.equals("UploadId")) {
+ uploadId = currentOrNull(currentText);
+ } else if (qName.equals("StorageClass")) {
+ storageClass = ObjectMetadata.StorageClass.valueOf(currentOrNull(currentText));
+ } else if (qName.equals("Initiated")) {
+ initiated = dateParser.iso8601DateOrSecondsDateParse(currentOrNull(currentText));
+ } else if (qName.equals("Upload")) {
+ uploads.add(ListMultipartUploadsResponse.Upload.create(key, uploadId, initiator, owner, storageClass, initiated));
+ key = null;
+ uploadId = null;
+ id = null;
+ displayName = null;
+ initiator = null;
+ owner = null;
+ storageClass = null;
+ initiated = null;
+ inUpload = false;
+ } else if (qName.equals("Initiator")) {
+ initiator = new CanonicalUser(id, displayName);
+ id = null;
+ displayName = null;
+ inInitiator = false;
+ } else if (qName.equals("Owner")) {
+ owner = new CanonicalUser(id, displayName);
+ id = null;
+ displayName = null;
+ inOwner = false;
+ }
+ }
+
+ public void characters(char ch[], int start, int length) {
+ currentText.append(ch, start, length);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/445664c9/apis/s3/src/test/java/org/jclouds/s3/S3ClientLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/test/java/org/jclouds/s3/S3ClientLiveTest.java b/apis/s3/src/test/java/org/jclouds/s3/S3ClientLiveTest.java
index a6ba2c7..a4b87a1 100644
--- a/apis/s3/src/test/java/org/jclouds/s3/S3ClientLiveTest.java
+++ b/apis/s3/src/test/java/org/jclouds/s3/S3ClientLiveTest.java
@@ -56,6 +56,7 @@ import org.jclouds.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.s3.domain.AccessControlList.Permission;
import org.jclouds.s3.domain.CannedAccessPolicy;
import org.jclouds.s3.domain.DeleteResult;
+import org.jclouds.s3.domain.ListMultipartUploadsResponse;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadataBuilder;
import org.jclouds.s3.domain.S3Object;
@@ -566,6 +567,35 @@ public class S3ClientLiveTest extends BaseBlobStoreIntegrationTest {
}
}
+ public void testListMultipartUploads() throws Exception {
+ String containerName = getContainerName();
+ String key = "testListMultipartUploads";
+ String uploadId = null;
+ try {
+ ListMultipartUploadsResponse response = getApi().listMultipartUploads(containerName, null, null, null, null, null);
+ assertThat(response.bucket()).isEqualTo(containerName);
+ assertThat(response.isTruncated()).isFalse();
+ assertThat(response.uploads()).isEmpty();
+
+ uploadId = getApi().initiateMultipartUpload(containerName, ObjectMetadataBuilder.create().key(key).build());
+
+ response = getApi().listMultipartUploads(containerName, null, null, null, null, null);
+ assertThat(response.bucket()).isEqualTo(containerName);
+ assertThat(response.isTruncated()).isFalse();
+ assertThat(response.uploads()).hasSize(1);
+
+ ListMultipartUploadsResponse.Upload upload = response.uploads().get(0);
+ assertThat(upload.key()).isEqualTo(key);
+ assertThat(upload.uploadId()).isEqualTo(uploadId);
+ assertThat(upload.storageClass()).isEqualTo(ObjectMetadata.StorageClass.STANDARD);
+ } finally {
+ if (uploadId != null) {
+ getApi().abortMultipartUpload(containerName, key, uploadId);
+ }
+ returnContainer(containerName);
+ }
+ }
+
public void testDeleteMultipleObjects() throws InterruptedException {
String container = getContainerName();
try {
http://git-wip-us.apache.org/repos/asf/jclouds/blob/445664c9/apis/s3/src/test/java/org/jclouds/s3/S3ClientTest.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/test/java/org/jclouds/s3/S3ClientTest.java b/apis/s3/src/test/java/org/jclouds/s3/S3ClientTest.java
index 75ff965..dae83a6 100644
--- a/apis/s3/src/test/java/org/jclouds/s3/S3ClientTest.java
+++ b/apis/s3/src/test/java/org/jclouds/s3/S3ClientTest.java
@@ -20,6 +20,7 @@ import static org.jclouds.reflect.Reflection2.method;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Map;
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
@@ -68,6 +69,7 @@ import org.jclouds.s3.xml.BucketLoggingHandler;
import org.jclouds.s3.xml.CopyObjectHandler;
import org.jclouds.s3.xml.ListAllMyBucketsHandler;
import org.jclouds.s3.xml.ListBucketHandler;
+import org.jclouds.s3.xml.ListMultipartUploadsHandler;
import org.jclouds.s3.xml.LocationConstraintHandler;
import org.jclouds.s3.xml.PayerHandler;
import org.jclouds.util.Strings2;
@@ -625,6 +627,22 @@ public abstract class S3ClientTest<T extends S3Client> extends BaseS3ClientTest<
checkFilters(request);
}
+ public void testListMultipartUploads() throws Exception {
+ Invokable<?, ?> method = method(S3Client.class, "listMultipartUploads", String.class, String.class,
+ Integer.class, String.class, String.class, String.class);
+ GeneratedHttpRequest request = processor.createRequest(method, Arrays.<Object> asList("bucket", null, null, null, null, null));
+
+ assertRequestLineEquals(request, "GET https://bucket." + url + "/?uploads HTTP/1.1");
+ assertNonPayloadHeadersEqual(request, "Host: bucket." + url + "\n");
+ assertPayloadEquals(request, null, "application/unknown", false);
+
+ assertResponseParserClassEquals(method, request, ParseSax.class);
+ assertSaxResponseParserClassEquals(method, ListMultipartUploadsHandler.class);
+ assertFallbackClassEquals(method, MapHttp4xxCodesToExceptions.class);
+
+ checkFilters(request);
+ }
+
@ConfiguresHttpApi
private static final class TestS3HttpApiModule extends S3HttpApiModule<S3Client> {