JCLOUDS-457: Added the retrieve output operations
Now the Glacier client can retrieve data.
diff --git a/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java b/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
index c3cee5b..541a3f4 100644
--- a/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
+++ b/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
@@ -32,6 +32,7 @@
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.blobstore.attr.BlobScope;
+import org.jclouds.glacier.binders.BindArchiveOutputRangeToHeaders;
import org.jclouds.glacier.binders.BindArchiveSizeToHeaders;
import org.jclouds.glacier.binders.BindContentRangeToHeaders;
import org.jclouds.glacier.binders.BindDescriptionToHeaders;
@@ -39,6 +40,7 @@
import org.jclouds.glacier.binders.BindJobRequestToJsonPayload;
import org.jclouds.glacier.binders.BindMultipartTreeHashToHeaders;
import org.jclouds.glacier.binders.BindPartSizeToHeaders;
+import org.jclouds.glacier.domain.ArchiveMetadataCollection;
import org.jclouds.glacier.domain.JobMetadata;
import org.jclouds.glacier.domain.JobRequest;
import org.jclouds.glacier.domain.MultipartUploadMetadata;
@@ -48,7 +50,9 @@
import org.jclouds.glacier.domain.VaultMetadata;
import org.jclouds.glacier.fallbacks.FalseOnIllegalArgumentException;
import org.jclouds.glacier.filters.RequestAuthorizeSignature;
+import org.jclouds.glacier.functions.GetPayloadFromHttpContent;
import org.jclouds.glacier.functions.ParseArchiveIdHeader;
+import org.jclouds.glacier.functions.ParseArchiveMetadataCollectionFromHttpContent;
import org.jclouds.glacier.functions.ParseJobIdHeader;
import org.jclouds.glacier.functions.ParseJobMetadataFromHttpContent;
import org.jclouds.glacier.functions.ParseJobMetadataListFromHttpContent;
@@ -313,4 +317,38 @@
@ResponseParser(ParseJobMetadataListFromHttpContent.class)
ListenableFuture<PaginatedJobCollection> listJobs(
@ParamValidators(VaultNameValidator.class) @PathParam("vault") String vaultName);
+
+ /**
+ * @see GlacierClient#getJobOutput
+ */
+ @Named("GetJobOutput")
+ @GET
+ @Path("/-/vaults/{vault}/jobs/{job}/output")
+ @ResponseParser(GetPayloadFromHttpContent.class)
+ ListenableFuture<Payload> getJobOutput(
+ @ParamValidators(VaultNameValidator.class) @PathParam("vault") String vaultName,
+ @PathParam("job") String jobId,
+ @BinderParam(BindArchiveOutputRangeToHeaders.class) ContentRange range);
+
+ /**
+ * @see GlacierClient#getJobOutput
+ */
+ @Named("GetJobOutput")
+ @GET
+ @Path("/-/vaults/{vault}/jobs/{job}/output")
+ @ResponseParser(GetPayloadFromHttpContent.class)
+ ListenableFuture<Payload> getJobOutput(
+ @ParamValidators(VaultNameValidator.class) @PathParam("vault") String vaultName,
+ @PathParam("job") String jobId);
+
+ /**
+ * @see GlacierClient#getInventoryRetrievalOutput
+ */
+ @Named("GetInventoryRetrievalOutput")
+ @GET
+ @Path("/-/vaults/{vault}/jobs/{job}/output")
+ @ResponseParser(ParseArchiveMetadataCollectionFromHttpContent.class)
+ ListenableFuture<ArchiveMetadataCollection> getInventoryRetrievalOutput(
+ @ParamValidators(VaultNameValidator.class) @PathParam("vault") String vaultName,
+ @PathParam("job") String jobId);
}
diff --git a/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java b/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
index ab8d694..da6fe7d 100644
--- a/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
+++ b/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
@@ -20,6 +20,7 @@
import java.net.URI;
import java.util.Map;
+import org.jclouds.glacier.domain.ArchiveMetadataCollection;
import org.jclouds.glacier.domain.JobMetadata;
import org.jclouds.glacier.domain.JobRequest;
import org.jclouds.glacier.domain.MultipartUploadMetadata;
@@ -262,4 +263,42 @@
* Lists jobs.
*/
PaginatedJobCollection listJobs(String vaultName);
+
+ /**
+ * Downloads part of the output of an archive retrieval job.
+ *
+ * @param vaultName
+ * Name of the target Vault for the job.
+ * @param jobId
+ * Job identifier.
+ * @param range
+ * The range of bytes to retrieve from the output.
+ * @return The content data.
+ * @see <a href="http://docs.aws.amazon.com/amazonglacier/latest/dev/api-job-output-get.html" />
+ */
+ Payload getJobOutput(String vaultName, String jobId, ContentRange range);
+
+ /**
+ * Downloads the output of an archive retrieval job.
+ *
+ * @param vaultName
+ * Name of the target Vault for the job.
+ * @param jobId
+ * Job identifier.
+ * @return The content data.
+ * @see <a href="http://docs.aws.amazon.com/amazonglacier/latest/dev/api-job-output-get.html" />
+ */
+ Payload getJobOutput(String vaultName, String jobId);
+
+ /**
+ * Downloads the output of an inventory retrieval job.
+ *
+ * @param vaultName
+ * Name of the target Vault for the job.
+ * @param jobId
+ * Job identifier.
+ * @return The ArchiveMetadata collection
+ * @see <a href="http://docs.aws.amazon.com/amazonglacier/latest/dev/api-job-output-get.html" />
+ */
+ ArchiveMetadataCollection getInventoryRetrievalOutput(String vaultName, String jobId);
}
diff --git a/glacier/src/main/java/org/jclouds/glacier/binders/BindArchiveOutputRangeToHeaders.java b/glacier/src/main/java/org/jclouds/glacier/binders/BindArchiveOutputRangeToHeaders.java
new file mode 100644
index 0000000..7afc68e
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/binders/BindArchiveOutputRangeToHeaders.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util.ContentRange;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+/**
+ * Binds the ContentRange to the request headers.
+ */
+public class BindArchiveOutputRangeToHeaders implements Binder {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+ checkArgument(input instanceof ContentRange, "This binder is only valid for ContentRange");
+ checkNotNull(request, "request");
+ ContentRange range = ContentRange.class.cast(input);
+ return (R) request.toBuilder().addHeader("Range", "bytes=" + range.toString()).build();
+ }
+
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/domain/ArchiveMetadata.java b/glacier/src/main/java/org/jclouds/glacier/domain/ArchiveMetadata.java
new file mode 100644
index 0000000..7611de8
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/domain/ArchiveMetadata.java
@@ -0,0 +1,103 @@
+/*
+ * 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.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.util.Date;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.hash.HashCode;
+import com.google.gson.annotations.SerializedName;
+
+public class ArchiveMetadata implements Comparable<ArchiveMetadata> {
+
+ @SerializedName("ArchiveId")
+ private final String archiveId;
+ @SerializedName("ArchiveDescription")
+ private final String description;
+ @SerializedName("CreationDate")
+ private final Date creationDate;
+ @SerializedName("Size")
+ private final long size;
+ @SerializedName("SHA256TreeHash")
+ private final HashCode treeHash;
+
+ @ConstructorProperties({ "ArchiveId", "ArchiveDescription", "CreationDate", "Size", "SHA256TreeHash" })
+ public ArchiveMetadata(String archiveId, @Nullable String description, Date creationDate, long size, String hashCode) {
+ this.archiveId = checkNotNull(archiveId, "archiveId");
+ this.description = description;
+ this.creationDate = (Date) checkNotNull(creationDate, "creationDate").clone();
+ this.size = size;
+ this.treeHash = HashCode.fromString(checkNotNull(hashCode, "hashCode"));
+ }
+
+ public String getArchiveId() {
+ return archiveId;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Date getCreationDate() {
+ return (Date) creationDate.clone();
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public HashCode getTreeHash() {
+ return treeHash;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.archiveId, this.description, this.creationDate, this.size, this.treeHash);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ArchiveMetadata other = (ArchiveMetadata) obj;
+
+ return Objects.equal(this.archiveId, other.archiveId)
+ && Objects.equal(this.description, other.description)
+ && Objects.equal(this.creationDate, other.creationDate)
+ && Objects.equal(this.treeHash, other.treeHash)
+ && Objects.equal(this.size, other.size);
+ }
+
+ @Override
+ public String toString() {
+ return "ArchiveMetadata [archiveId=" + archiveId + ", description=" + description
+ + ", creationDate=" + creationDate + ", treeHash=" + treeHash + ", size=" + size + "]";
+ }
+
+ @Override
+ public int compareTo(ArchiveMetadata o) {
+ return ComparisonChain.start().compare(this.archiveId, o.archiveId).result();
+ }
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/domain/ArchiveMetadataCollection.java b/glacier/src/main/java/org/jclouds/glacier/domain/ArchiveMetadataCollection.java
new file mode 100644
index 0000000..4f908b6
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/domain/ArchiveMetadataCollection.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.glacier.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.util.Date;
+import java.util.Iterator;
+
+import com.google.common.collect.FluentIterable;
+import com.google.gson.annotations.SerializedName;
+
+
+public class ArchiveMetadataCollection extends FluentIterable<ArchiveMetadata>{
+
+ @SerializedName("ArchiveList")
+ private final Iterable<ArchiveMetadata> archives;
+ @SerializedName("VaultARN")
+ private final String vaultARN;
+ @SerializedName("InventoryDate")
+ private final Date inventoryDate;
+
+ @ConstructorProperties({ "ArchiveList", "VaultARN", "InventoryDate" })
+ public ArchiveMetadataCollection(Iterable<ArchiveMetadata> archives, String vaultARN, Date inventoryDate) {
+ this.archives = checkNotNull(archives, "archives");
+ this.vaultARN = checkNotNull(vaultARN, "vaultARN");
+ this.inventoryDate = (Date) checkNotNull(inventoryDate, "inventoryDate").clone();
+ }
+
+ @Override
+ public Iterator<ArchiveMetadata> iterator() {
+ return archives.iterator();
+ }
+
+ public String getVaultARN() {
+ return vaultARN;
+ }
+
+ public Date getInventoryDate() {
+ return (Date) inventoryDate.clone();
+ }
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/functions/GetPayloadFromHttpContent.java b/glacier/src/main/java/org/jclouds/glacier/functions/GetPayloadFromHttpContent.java
new file mode 100644
index 0000000..12e07da
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/functions/GetPayloadFromHttpContent.java
@@ -0,0 +1,36 @@
+/*
+ * 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.functions;
+
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.io.Payload;
+
+import com.google.common.base.Function;
+
+/**
+ * Gets the payload from the http response.
+ */
+public class GetPayloadFromHttpContent implements Function<HttpResponse, Payload> {
+
+ @Override
+ public Payload apply(HttpResponse from) {
+ if (from.getPayload() == null)
+ throw new HttpException("Did not receive payload");
+ return from.getPayload();
+ }
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/functions/ParseArchiveMetadataCollectionFromHttpContent.java b/glacier/src/main/java/org/jclouds/glacier/functions/ParseArchiveMetadataCollectionFromHttpContent.java
new file mode 100644
index 0000000..ae224c2
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/functions/ParseArchiveMetadataCollectionFromHttpContent.java
@@ -0,0 +1,32 @@
+/*
+ * 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.functions;
+
+import org.jclouds.glacier.domain.ArchiveMetadataCollection;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+public class ParseArchiveMetadataCollectionFromHttpContent extends ParseJson<ArchiveMetadataCollection> {
+
+ @Inject
+ public ParseArchiveMetadataCollectionFromHttpContent(Json json) {
+ super(json, TypeLiteral.get(ArchiveMetadataCollection.class));
+ }
+}
diff --git a/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java b/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
index b3ac6c2..c23818a 100644
--- a/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
+++ b/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
@@ -37,6 +37,8 @@
import org.jclouds.ContextBuilder;
import org.jclouds.concurrent.config.ExecutorServiceModule;
+import org.jclouds.glacier.domain.ArchiveMetadata;
+import org.jclouds.glacier.domain.ArchiveMetadataCollection;
import org.jclouds.glacier.domain.ArchiveRetrievalJobRequest;
import org.jclouds.glacier.domain.InventoryRetrievalJobRequest;
import org.jclouds.glacier.domain.JobMetadata;
@@ -50,6 +52,7 @@
import org.jclouds.glacier.reference.GlacierHeaders;
import org.jclouds.glacier.util.ContentRange;
import org.jclouds.http.HttpResponseException;
+import org.jclouds.io.ByteSources;
import org.jclouds.io.Payload;
import org.jclouds.json.Json;
import org.jclouds.json.internal.GsonWrapper;
@@ -471,4 +474,59 @@
assertFalse(i.hasNext());
assertEquals(server.takeRequest().getRequestLine(), "GET /-/vaults/examplevault/jobs HTTP/1.1");
}
+
+ @Test
+ public void testGetJobOutput() throws IOException, InterruptedException {
+ MockResponse mr = buildBaseResponse(200);
+ mr.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8);
+ mr.setBody(getResponseBody("/json/getJobOutputResponseBody.json"));
+ mr.addHeader(HttpHeaders.CONTENT_LENGTH, mr.getBody().length);
+ server.enqueue(mr);
+
+ Payload payload = client.getJobOutput(VAULT_NAME, JOB_ID);
+ assertEquals(payload.getContentMetadata().getContentType(), MediaType.JSON_UTF_8.toString());
+ assertEquals(payload.getContentMetadata().getContentLength(), new Long(mr.getBody().length));
+ assertEquals(ByteSources.asByteSource(payload.openStream()).size(), mr.getBody().length);
+ assertEquals(server.takeRequest().getRequestLine(),
+ "GET /-/vaults/" + VAULT_NAME + "/jobs/" + JOB_ID + "/output " + HTTP);
+ }
+
+ @Test
+ public void testGetJobOutputWithContentRange() throws IOException, InterruptedException {
+ MockResponse mr = buildBaseResponse(206);
+ mr.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8);
+ mr.setBody(getResponseBody("/json/getJobOutputResponseBody.json"));
+ mr.addHeader(HttpHeaders.CONTENT_LENGTH, mr.getBody().length);
+ server.enqueue(mr);
+
+ ContentRange range = ContentRange.fromString("16-32");
+ client.getJobOutput(VAULT_NAME, JOB_ID, range);
+ RecordedRequest request = server.takeRequest();
+ assertEquals(request.getHeader("Range"), "bytes=" + range.toString());
+ assertEquals(request.getRequestLine(),
+ "GET /-/vaults/" + VAULT_NAME + "/jobs/" + JOB_ID + "/output " + HTTP);
+ }
+
+ @Test
+ public void testGetInventoryRetrievalOutput() throws IOException, InterruptedException {
+ MockResponse mr = buildBaseResponse(200);
+ mr.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8);
+ mr.setBody(getResponseBody("/json/getJobOutputResponseBody.json"));
+ mr.addHeader(HttpHeaders.CONTENT_LENGTH, mr.getBody().length);
+ server.enqueue(mr);
+
+ ArchiveMetadataCollection archives = client.getInventoryRetrievalOutput(VAULT_NAME, JOB_ID);
+ assertEquals(archives.getVaultARN(), "arn:aws:glacier:us-east-1:012345678901:vaults/examplevault");
+ Iterator<ArchiveMetadata> i = archives.iterator();
+ ArchiveMetadata archive = i.next();
+ assertEquals(archive.getArchiveId(),
+ "DMTmICA2n5Tdqq5BV2z7og-A20xnpAPKt3UXwWxdWsn_D6auTUrW6kwy5Qyj9xd1MCE1mBYvMQ63LWaT8yTMzMaCxB_9VBWrW4Jw4zsvg5kehAPDVKcppUD1X7b24JukOr4mMAq-oA");
+ assertEquals(archive.getDescription(), "my archive1");
+ assertEquals(archive.getSize(), 2140123);
+ assertEquals(archive.getTreeHash(),
+ HashCode.fromString("6b9d4cf8697bd3af6aa1b590a0b27b337da5b18988dbcc619a3e608a554a1e62"));
+ assertTrue(i.hasNext());
+ i.next();
+ assertFalse(i.hasNext());
+ }
}
diff --git a/glacier/src/test/resources/json/getJobOutputResponseBody.json b/glacier/src/test/resources/json/getJobOutputResponseBody.json
new file mode 100644
index 0000000..4715d91
--- /dev/null
+++ b/glacier/src/test/resources/json/getJobOutputResponseBody.json
@@ -0,0 +1,20 @@
+{
+ "VaultARN": "arn:aws:glacier:us-east-1:012345678901:vaults/examplevault",
+ "InventoryDate": "2011-12-12T14:19:01Z",
+ "ArchiveList": [
+ {
+ "ArchiveId": "DMTmICA2n5Tdqq5BV2z7og-A20xnpAPKt3UXwWxdWsn_D6auTUrW6kwy5Qyj9xd1MCE1mBYvMQ63LWaT8yTMzMaCxB_9VBWrW4Jw4zsvg5kehAPDVKcppUD1X7b24JukOr4mMAq-oA",
+ "ArchiveDescription": "my archive1",
+ "CreationDate": "2012-05-15T17:19:46.700Z",
+ "Size": 2140123,
+ "SHA256TreeHash": "6b9d4cf8697bd3af6aa1b590a0b27b337da5b18988dbcc619a3e608a554a1e62"
+ },
+ {
+ "ArchiveId": "2lHzwhKhgF2JHyvCS-ZRuF08IQLuyB4265Hs3AXj9MoAIhz7tbXAvcFeHusgU_hViO1WeCBe0N5lsYYHRyZ7rrmRkNRuYrXUs_sjl2K8ume_7mKO_0i7C-uHE1oHqaW9d37pabXrSA",
+ "ArchiveDescription": "my archive2",
+ "CreationDate": "2012-05-15T17:21:39.339Z",
+ "Size": 2140123,
+ "SHA256TreeHash": "7f2fe580edb35154041fa3d4b41dd6d3adaef0c85d2ff6309f1d4b520eeecda3"
+ }
+ ]
+}