Skip to content

Commit 91da041

Browse files
authored
Adding serialization capability to ResumableFileDownload (#3177)
* Adding serialization capability to ResumableFileDownload
1 parent 3c9adc2 commit 91da041

File tree

15 files changed

+1459
-5
lines changed

15 files changed

+1459
-5
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "S3 Transfer Manager (Developer Preview)",
3+
"contributor": "",
4+
"type": "feature",
5+
"description": "Add serialization capability to ResumableFileDownload, allowing users to persist paused downloads"
6+
}
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.protocols.jsoncore;
17+
18+
import static software.amazon.awssdk.protocols.jsoncore.JsonNodeParser.DEFAULT_JSON_FACTORY;
19+
import static software.amazon.awssdk.utils.DateUtils.formatUnixTimestampInstant;
20+
21+
import java.io.ByteArrayOutputStream;
22+
import java.io.IOException;
23+
import java.math.BigDecimal;
24+
import java.math.BigInteger;
25+
import java.nio.ByteBuffer;
26+
import java.time.Instant;
27+
import software.amazon.awssdk.annotations.SdkProtectedApi;
28+
import software.amazon.awssdk.thirdparty.jackson.core.JsonFactory;
29+
import software.amazon.awssdk.thirdparty.jackson.core.JsonGenerator;
30+
import software.amazon.awssdk.utils.BinaryUtils;
31+
import software.amazon.awssdk.utils.FunctionalUtils;
32+
import software.amazon.awssdk.utils.SdkAutoCloseable;
33+
34+
/**
35+
* Thin wrapper around Jackson's JSON generator.
36+
*/
37+
@SdkProtectedApi
38+
public class JsonWriter implements SdkAutoCloseable {
39+
40+
private static final int DEFAULT_BUFFER_SIZE = 1024;
41+
private final JsonFactory jsonFactory;
42+
private final ByteArrayOutputStream baos;
43+
private final JsonGenerator generator;
44+
45+
private JsonWriter(Builder builder) {
46+
jsonFactory = builder.jsonFactory != null ? builder.jsonFactory : DEFAULT_JSON_FACTORY;
47+
try {
48+
baos = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
49+
generator = jsonFactory.createGenerator(baos);
50+
} catch (IOException e) {
51+
throw new JsonGenerationException(e);
52+
}
53+
}
54+
55+
public static JsonWriter create() {
56+
return builder().build();
57+
}
58+
59+
public static JsonWriter.Builder builder() {
60+
return new Builder();
61+
}
62+
63+
public JsonWriter writeStartArray() {
64+
return unsafeWrite(generator::writeStartArray);
65+
}
66+
67+
public JsonWriter writeEndArray() {
68+
return unsafeWrite(generator::writeEndArray);
69+
}
70+
71+
public JsonWriter writeNull() {
72+
return unsafeWrite(generator::writeEndArray);
73+
}
74+
75+
public JsonWriter writeStartObject() {
76+
return unsafeWrite(generator::writeStartObject);
77+
}
78+
79+
public JsonWriter writeEndObject() {
80+
return unsafeWrite(generator::writeEndObject);
81+
}
82+
83+
public JsonWriter writeFieldName(String fieldName) {
84+
return unsafeWrite(() -> generator.writeFieldName(fieldName));
85+
}
86+
87+
public JsonWriter writeValue(String val) {
88+
return unsafeWrite(() -> generator.writeString(val));
89+
}
90+
91+
public JsonWriter writeValue(boolean bool) {
92+
return unsafeWrite(() -> generator.writeBoolean(bool));
93+
}
94+
95+
public JsonWriter writeValue(long val) {
96+
return unsafeWrite(() -> generator.writeNumber(val));
97+
}
98+
99+
public JsonWriter writeValue(double val) {
100+
return unsafeWrite(() -> generator.writeNumber(val));
101+
}
102+
103+
public JsonWriter writeValue(float val) {
104+
return unsafeWrite(() -> generator.writeNumber(val));
105+
}
106+
107+
public JsonWriter writeValue(short val) {
108+
return unsafeWrite(() -> generator.writeNumber(val));
109+
}
110+
111+
public JsonWriter writeValue(int val) {
112+
return unsafeWrite(() -> generator.writeNumber(val));
113+
}
114+
115+
public JsonWriter writeValue(ByteBuffer bytes) {
116+
return unsafeWrite(() -> generator.writeBinary(BinaryUtils.copyBytesFrom(bytes)));
117+
}
118+
119+
public JsonWriter writeValue(Instant instant) {
120+
return unsafeWrite(() -> generator.writeNumber(formatUnixTimestampInstant(instant)));
121+
}
122+
123+
public JsonWriter writeValue(BigDecimal value) {
124+
return unsafeWrite(() -> generator.writeString(value.toString()));
125+
}
126+
127+
public JsonWriter writeValue(BigInteger value) {
128+
return unsafeWrite(() -> generator.writeNumber(value));
129+
}
130+
131+
public JsonWriter writeNumber(String number) {
132+
return unsafeWrite(() -> generator.writeNumber(number));
133+
}
134+
135+
/**
136+
* Closes the generator and flushes to write. Must be called when finished writing JSON
137+
* content.
138+
*/
139+
@Override
140+
public void close() {
141+
try {
142+
generator.close();
143+
} catch (IOException e) {
144+
throw new JsonGenerationException(e);
145+
}
146+
}
147+
148+
/**
149+
* Get the JSON content as a UTF-8 encoded byte array. It is recommended to hold onto the array
150+
* reference rather then making repeated calls to this method as a new array will be created
151+
* each time.
152+
*
153+
* @return Array of UTF-8 encoded bytes that make up the generated JSON.
154+
*/
155+
public byte[] getBytes() {
156+
close();
157+
return baos.toByteArray();
158+
}
159+
160+
private JsonWriter unsafeWrite(FunctionalUtils.UnsafeRunnable r) {
161+
try {
162+
r.run();
163+
} catch (Exception e) {
164+
throw new JsonGenerationException(e);
165+
}
166+
return this;
167+
}
168+
169+
/**
170+
* A builder for configuring and creating {@link JsonWriter}. Created via {@link #builder()}.
171+
*/
172+
public static final class Builder {
173+
private JsonFactory jsonFactory;
174+
175+
private Builder() {
176+
}
177+
178+
/**
179+
* The {@link JsonFactory} implementation to be used when parsing the input. This allows JSON extensions like CBOR or
180+
* Ion to be supported.
181+
*
182+
* <p>It's highly recommended us use a shared {@code JsonFactory} where possible, so they should be stored statically:
183+
* http://wiki.fasterxml.com/JacksonBestPracticesPerformance
184+
*
185+
* <p>By default, this is {@link JsonNodeParser#DEFAULT_JSON_FACTORY}.
186+
*/
187+
public JsonWriter.Builder jsonFactory(JsonFactory jsonFactory) {
188+
this.jsonFactory = jsonFactory;
189+
return this;
190+
}
191+
192+
/**
193+
* Build a {@link JsonNodeParser} based on the current configuration of this builder.
194+
*/
195+
public JsonWriter build() {
196+
return new JsonWriter(this);
197+
}
198+
}
199+
200+
/**
201+
* Indicates an issue writing JSON content.
202+
*/
203+
public static class JsonGenerationException extends RuntimeException {
204+
205+
public JsonGenerationException(Throwable t) {
206+
super(t);
207+
}
208+
}
209+
}

services-custom/s3-transfer-manager/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@
101101
<artifactId>aws-core</artifactId>
102102
<version>${awsjavasdk.version}</version>
103103
</dependency>
104+
<dependency>
105+
<groupId>software.amazon.awssdk</groupId>
106+
<artifactId>json-utils</artifactId>
107+
<version>${awsjavasdk.version}</version>
108+
</dependency>
109+
<dependency>
110+
<groupId>software.amazon.awssdk</groupId>
111+
<artifactId>protocol-core</artifactId>
112+
<version>${awsjavasdk.version}</version>
113+
</dependency>
104114
<dependency>
105115
<groupId>software.amazon.awssdk</groupId>
106116
<artifactId>service-test-utils</artifactId>

services-custom/s3-transfer-manager/src/main/java/software/amazon/awssdk/transfer/s3/FileDownload.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ public interface FileDownload extends ObjectTransfer {
3131
/**
3232
* Pause the current download operation and returns the information that can
3333
* be used to resume the download at a later time.
34+
* <p>
35+
* The information object is serializable for persistent storage until it should be resumed.
36+
* See {@link ResumableFileDownload} for supported formats.
3437
*
3538
* @return {@link ResumableFileDownload} that can be used to resume the download
3639
*/

0 commit comments

Comments
 (0)