17
17
import software .amazon .awssdk .services .s3 .model .AbortMultipartUploadResponse ;
18
18
import software .amazon .awssdk .services .s3 .model .CompleteMultipartUploadRequest ;
19
19
import software .amazon .awssdk .services .s3 .model .CompleteMultipartUploadResponse ;
20
- import software .amazon .awssdk .services .s3 .model .CompletedPart ;
21
20
import software .amazon .awssdk .services .s3 .model .CreateMultipartUploadRequest ;
22
21
import software .amazon .awssdk .services .s3 .model .CreateMultipartUploadResponse ;
23
22
import software .amazon .awssdk .services .s3 .model .DeleteObjectRequest ;
32
31
import software .amazon .awssdk .services .s3 .model .UploadPartRequest ;
33
32
import software .amazon .awssdk .services .s3 .model .UploadPartResponse ;
34
33
import software .amazon .encryption .s3 .internal .GetEncryptedObjectPipeline ;
35
- import software .amazon .encryption .s3 .internal .MultiFileOutputStream ;
36
34
import software .amazon .encryption .s3 .internal .MultipartUploadObjectPipeline ;
37
35
import software .amazon .encryption .s3 .internal .PutEncryptedObjectPipeline ;
38
- import software .amazon .encryption .s3 .internal .UploadObjectObserver ;
39
36
import software .amazon .encryption .s3 .materials .AesKeyring ;
40
37
import software .amazon .encryption .s3 .materials .CryptographicMaterialsManager ;
41
38
import software .amazon .encryption .s3 .materials .DefaultCryptoMaterialsManager ;
42
39
import software .amazon .encryption .s3 .materials .Keyring ;
43
40
import software .amazon .encryption .s3 .materials .KmsKeyring ;
44
- import software .amazon .encryption .s3 .materials .MultipartConfiguration ;
45
41
import software .amazon .encryption .s3 .materials .PartialRsaKeyPair ;
46
42
import software .amazon .encryption .s3 .materials .RsaKeyring ;
47
43
48
44
import javax .crypto .SecretKey ;
49
- import java .io .IOException ;
50
45
import java .security .KeyPair ;
51
46
import java .security .Provider ;
52
47
import java .security .SecureRandom ;
53
- import java .util .ArrayList ;
54
48
import java .util .List ;
55
49
import java .util .Map ;
56
50
import java .util .concurrent .CompletableFuture ;
57
51
import java .util .concurrent .CompletionException ;
58
- import java .util .concurrent .ExecutionException ;
59
- import java .util .concurrent .ExecutorService ;
60
52
import java .util .concurrent .Executors ;
61
- import java .util .concurrent .Future ;
62
53
import java .util .function .Consumer ;
63
54
64
55
import static software .amazon .encryption .s3 .S3EncryptionClientUtilities .INSTRUCTION_FILE_SUFFIX ;
@@ -72,11 +63,11 @@ public class S3EncryptionClient implements S3Client {
72
63
73
64
// Used for request-scoped encryption contexts for supporting keys
74
65
public static final ExecutionAttribute <Map <String , String >> ENCRYPTION_CONTEXT = new ExecutionAttribute <>("EncryptionContext" );
75
- public static final ExecutionAttribute <MultipartConfiguration > CONFIGURATION = new ExecutionAttribute <>("MultipartConfiguration" );
76
66
// TODO: Replace with UploadPartRequest.isLastPart() when launched.
77
67
// Used for multipart uploads
78
68
public static final ExecutionAttribute <Boolean > IS_LAST_PART = new ExecutionAttribute <>("isLastPart" );
79
- private final S3AsyncClient _wrappedAsyncClient ;
69
+ private final S3AsyncClient _wrappedClient ;
70
+ private final S3AsyncClient _wrappedCrtClient ;
80
71
private final CryptographicMaterialsManager _cryptoMaterialsManager ;
81
72
private final SecureRandom _secureRandom ;
82
73
private final boolean _enableLegacyWrappingAlgorithms ;
@@ -86,7 +77,8 @@ public class S3EncryptionClient implements S3Client {
86
77
private final MultipartUploadObjectPipeline _multipartPipeline ;
87
78
88
79
private S3EncryptionClient (Builder builder ) {
89
- _wrappedAsyncClient = builder ._wrappedAsyncClient ;
80
+ _wrappedClient = builder ._wrappedClient ;
81
+ _wrappedCrtClient = builder ._wrappedCrtClient ;
90
82
_cryptoMaterialsManager = builder ._cryptoMaterialsManager ;
91
83
_secureRandom = builder ._secureRandom ;
92
84
_enableLegacyWrappingAlgorithms = builder ._enableLegacyWrappingAlgorithms ;
@@ -106,13 +98,6 @@ public static Consumer<AwsRequestOverrideConfiguration.Builder> withAdditionalCo
106
98
builder .putExecutionAttribute (S3EncryptionClient .ENCRYPTION_CONTEXT , encryptionContext );
107
99
}
108
100
109
- // Helper function to attach encryption contexts to a request
110
- public static Consumer <AwsRequestOverrideConfiguration .Builder > withAdditionalConfiguration (Map <String , String > encryptionContext , MultipartConfiguration multipartConfiguration ) {
111
- return builder ->
112
- builder .putExecutionAttribute (S3EncryptionClient .ENCRYPTION_CONTEXT , encryptionContext )
113
- .putExecutionAttribute (S3EncryptionClient .CONFIGURATION , multipartConfiguration );
114
- }
115
-
116
101
// Helper function to determine last upload part during multipart uploads
117
102
public static Consumer <AwsRequestOverrideConfiguration .Builder > isLastPart (Boolean isLastPart ) {
118
103
return builder ->
@@ -123,21 +108,11 @@ public static Consumer<AwsRequestOverrideConfiguration.Builder> isLastPart(Boole
123
108
public PutObjectResponse putObject (PutObjectRequest putObjectRequest , RequestBody requestBody )
124
109
throws AwsServiceException , SdkClientException {
125
110
126
- if (_enableMultipartPutObject ) {
127
- try {
128
- // TODO: Confirm best way to wrap CompleteMultipartUploadResponse with PutObjectResponse
129
- CompleteMultipartUploadResponse completeResponse = multipartPutObject (putObjectRequest , requestBody );
130
- PutObjectResponse response = PutObjectResponse .builder ()
131
- .eTag (completeResponse .eTag ())
132
- .build ();
133
- return response ;
134
- } catch (Throwable e ) {
135
- throw new S3EncryptionClientException ("Exception while performing Multipart Upload PutObject" , e );
136
- }
137
- }
138
111
PutEncryptedObjectPipeline pipeline = PutEncryptedObjectPipeline .builder ()
139
- .s3AsyncClient (_wrappedAsyncClient )
112
+ .s3AsyncClient (_wrappedClient )
113
+ .crtClient (_wrappedCrtClient )
140
114
.cryptoMaterialsManager (_cryptoMaterialsManager )
115
+ .enableMultipartPutObject (_enableMultipartPutObject )
141
116
.secureRandom (_secureRandom )
142
117
.build ();
143
118
@@ -151,7 +126,7 @@ public <T> T getObject(GetObjectRequest getObjectRequest,
151
126
throws AwsServiceException , SdkClientException {
152
127
153
128
GetEncryptedObjectPipeline pipeline = GetEncryptedObjectPipeline .builder ()
154
- .s3AsyncClient (_wrappedAsyncClient )
129
+ .s3AsyncClient (_wrappedClient )
155
130
.cryptoMaterialsManager (_cryptoMaterialsManager )
156
131
.enableLegacyWrappingAlgorithms (_enableLegacyWrappingAlgorithms )
157
132
.enableLegacyUnauthenticatedModes (_enableLegacyUnauthenticatedModes )
@@ -168,76 +143,14 @@ public <T> T getObject(GetObjectRequest getObjectRequest,
168
143
}
169
144
}
170
145
171
- private CompleteMultipartUploadResponse multipartPutObject (PutObjectRequest request , RequestBody requestBody ) throws Throwable {
172
-
173
- AwsRequestOverrideConfiguration overrideConfig = request .overrideConfiguration ().get ();
174
- // If MultipartConfiguration is null, Initialize MultipartConfiguration
175
- MultipartConfiguration multipartConfiguration = overrideConfig
176
- .executionAttributes ()
177
- .getOptionalAttribute (S3EncryptionClient .CONFIGURATION )
178
- .orElse (MultipartConfiguration .builder ().build ());
179
-
180
- ExecutorService es = multipartConfiguration .executorService ();
181
- final boolean defaultExecutorService = es == null ;
182
- if (es == null ) {
183
- throw new S3EncryptionClientException ("ExecutorService should not be null, Please initialize during MultipartConfiguration" );
184
- }
185
-
186
- UploadObjectObserver observer = multipartConfiguration .uploadObjectObserver ();
187
- if (observer == null ) {
188
- throw new S3EncryptionClientException ("UploadObjectObserver should not be null, Please initialize during MultipartConfiguration" );
189
- }
190
-
191
- observer .init (request , _wrappedAsyncClient , this , es );
192
- final String uploadId = observer .onUploadCreation (request );
193
- final List <CompletedPart > partETags = new ArrayList <>();
194
-
195
- MultiFileOutputStream outputStream = multipartConfiguration .multiFileOutputStream ();
196
- if (outputStream == null ) {
197
- throw new S3EncryptionClientException ("MultiFileOutputStream should not be null, Please initialize during MultipartConfiguration" );
198
- }
199
-
200
- try {
201
- // initialize the multi-file output stream
202
- outputStream .init (observer , multipartConfiguration .partSize (), multipartConfiguration .diskLimit ());
203
- // Kicks off the encryption-upload pipeline;
204
- // Note outputStream is automatically closed upon method completion.
205
- _multipartPipeline .putLocalObject (requestBody , uploadId , outputStream );
206
- // block till all part have been uploaded
207
- for (Future <Map <Integer , UploadPartResponse >> future : observer .futures ()) {
208
- Map <Integer , UploadPartResponse > partResponseMap = future .get ();
209
- partResponseMap .forEach ((partNumber , uploadPartResponse ) -> partETags .add (CompletedPart .builder ()
210
- .partNumber (partNumber )
211
- .eTag (uploadPartResponse .eTag ())
212
- .build ()));
213
- }
214
- } catch (IOException | InterruptedException | ExecutionException | RuntimeException | Error ex ) {
215
- throw onAbort (observer , ex );
216
- } finally {
217
- if (defaultExecutorService ) {
218
- // shut down the locally created thread pool
219
- es .shutdownNow ();
220
- }
221
- // delete left-over temp files
222
- outputStream .cleanup ();
223
- }
224
- // Complete upload
225
- return observer .onCompletion (partETags );
226
- }
227
-
228
- private <T extends Throwable > T onAbort (UploadObjectObserver observer , T t ) {
229
- observer .onAbort ();
230
- return t ;
231
- }
232
-
233
146
@ Override
234
147
public DeleteObjectResponse deleteObject (DeleteObjectRequest deleteObjectRequest ) throws AwsServiceException ,
235
148
SdkClientException {
236
149
// Delete the object
237
- DeleteObjectResponse deleteObjectResponse = _wrappedAsyncClient .deleteObject (deleteObjectRequest ).join ();
150
+ DeleteObjectResponse deleteObjectResponse = _wrappedClient .deleteObject (deleteObjectRequest ).join ();
238
151
// If Instruction file exists, delete the instruction file as well.
239
152
String instructionObjectKey = deleteObjectRequest .key () + INSTRUCTION_FILE_SUFFIX ;
240
- _wrappedAsyncClient .deleteObject (builder -> builder
153
+ _wrappedClient .deleteObject (builder -> builder
241
154
.bucket (deleteObjectRequest .bucket ())
242
155
.key (instructionObjectKey )).join ();
243
156
return deleteObjectResponse ;
@@ -247,10 +160,10 @@ public DeleteObjectResponse deleteObject(DeleteObjectRequest deleteObjectRequest
247
160
public DeleteObjectsResponse deleteObjects (DeleteObjectsRequest deleteObjectsRequest ) throws AwsServiceException ,
248
161
SdkClientException {
249
162
// Delete the objects
250
- DeleteObjectsResponse deleteObjectsResponse = _wrappedAsyncClient .deleteObjects (deleteObjectsRequest ).join ();
163
+ DeleteObjectsResponse deleteObjectsResponse = _wrappedClient .deleteObjects (deleteObjectsRequest ).join ();
251
164
// If Instruction files exists, delete the instruction files as well.
252
165
List <ObjectIdentifier > deleteObjects = instructionFileKeysToDelete (deleteObjectsRequest );
253
- _wrappedAsyncClient .deleteObjects (DeleteObjectsRequest .builder ()
166
+ _wrappedClient .deleteObjects (DeleteObjectsRequest .builder ()
254
167
.bucket (deleteObjectsRequest .bucket ())
255
168
.delete (builder -> builder .objects (deleteObjects ))
256
169
.build ()).join ();
@@ -295,16 +208,17 @@ public AbortMultipartUploadResponse abortMultipartUpload(AbortMultipartUploadReq
295
208
296
209
@ Override
297
210
public String serviceName () {
298
- return _wrappedAsyncClient .serviceName ();
211
+ return _wrappedClient .serviceName ();
299
212
}
300
213
301
214
@ Override
302
215
public void close () {
303
- _wrappedAsyncClient .close ();
216
+ _wrappedClient .close ();
304
217
}
305
218
306
219
public static class Builder {
307
- private S3AsyncClient _wrappedAsyncClient = S3AsyncClient .create ();
220
+ private S3AsyncClient _wrappedClient = S3AsyncClient .create ();
221
+ private S3AsyncClient _wrappedCrtClient = null ;
308
222
309
223
private MultipartUploadObjectPipeline _multipartPipeline ;
310
224
private CryptographicMaterialsManager _cryptoMaterialsManager ;
@@ -327,22 +241,13 @@ private Builder() {
327
241
* S3AsyncClient will be reflected in this Builder.
328
242
*/
329
243
@ SuppressFBWarnings (value = "EI_EXPOSE_REP2" , justification = "Pass mutability into wrapping client" )
330
- public Builder wrappedAsyncClient (S3AsyncClient _wrappedAsyncClient ) {
331
- if (_wrappedAsyncClient instanceof S3AsyncEncryptionClient ) {
332
- throw new S3EncryptionClientException ("Cannot use S3EncryptionClient as wrapped client" );
244
+ public Builder wrappedClient (S3AsyncClient wrappedClient ) {
245
+ if (wrappedClient instanceof S3AsyncEncryptionClient ) {
246
+ throw new S3EncryptionClientException ("Cannot use S3AsyncEncryptionClient as wrapped client" );
333
247
}
334
-
335
- this ._wrappedAsyncClient = _wrappedAsyncClient ;
336
- return this ;
337
- }
338
-
339
- @ SuppressFBWarnings (value = "EI_EXPOSE_REP2" , justification = "Pass mutability into wrapping client" )
340
- public Builder _wrappedAsyncClient (S3AsyncClient _wrappedAsyncClient ) {
341
- if (_wrappedAsyncClient instanceof S3AsyncEncryptionClient ) {
342
- throw new S3EncryptionClientException ("Cannot use S3EncryptionClient as wrapped client" );
343
- }
344
-
345
- this ._wrappedAsyncClient = _wrappedAsyncClient ;
248
+ // Initializes only when wrappedClient is configured by user.
249
+ this ._wrappedCrtClient = wrappedClient ;
250
+ this ._wrappedClient = wrappedClient ;
346
251
return this ;
347
252
}
348
253
@@ -480,7 +385,7 @@ public S3EncryptionClient build() {
480
385
}
481
386
482
387
_multipartPipeline = MultipartUploadObjectPipeline .builder ()
483
- .s3AsyncClient (_wrappedAsyncClient )
388
+ .s3AsyncClient (_wrappedClient )
484
389
.cryptoMaterialsManager (_cryptoMaterialsManager )
485
390
.secureRandom (_secureRandom )
486
391
.build ();
0 commit comments