Skip to content

Commit 9542bd1

Browse files
ericjdingkeithelejohnlcoxmxue-BBfmbz
authored
Merge SSE and file lock updates to api (#149)
* merge SSE and File Lock updates to public repository * update ChangeLog and version number to 5.0.0 * add pip3 install of setuptools_scm to travis.yml * unset B2_APPLICATION_KEY before calling b2 upload_file in maybe_upload_build_results Co-authored-by: Keith Felt <[email protected]> Co-authored-by: keithele <[email protected]> Co-authored-by: John Leacox <[email protected]> Co-authored-by: mxue-BB <[email protected]> Co-authored-by: Fabian <[email protected]> Co-authored-by: fmbz <[email protected]> Co-authored-by: malaysf <[email protected]>
1 parent 0ecd68d commit 9542bd1

File tree

73 files changed

+4560
-192
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+4560
-192
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ env:
1818

1919
before_install:
2020
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties
21+
- pip3 install "setuptools_scm[toml]<6.0"
2122
- pip3 install b2
2223

2324
script:

CHANGELOG.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
# Changelog
22

3-
## [Unreleased]
4-
5-
## [5.0.0] - 2021-01-20
6-
### Added
7-
* added an asynchronous large file upload method `B2StorageClient.storeLargeFileFromLocalContentAsync`
3+
## [5.0.0] - 2021-05-10
84
### Changed `[Incompatible]`
9-
* Disable automatic decompressing compressed content in HTTP client download library
5+
* Disabled automatic decompression of compressed content in HTTP client download library
6+
* Added `updateFileRetention` and `updateLegalHold` to `B2StorageClient`
7+
* Added `storeLargeFileFromLocalContentAsync` to `B2StorageClient` to support asynchronous large file uploads
108

119
### Added
10+
* Added Server-Side Encryption (SSE) support to relevant API requests/responses
11+
* Added File Lock support to relevant API requests/responses
1212
* Set gradle targetCompatibility to 1.8
1313
* Added support for java.util.SortedMap interface
1414
* Support more than 64 fields per object
1515

1616
### Fixed
17-
* Fix regular expression that has an unescaped .
17+
* Fixed regular expression that had an unescaped '.'
1818

1919
## [4.0.0] - 2020-05-11
2020
### Added

core/src/main/java/com/backblaze/b2/client/B2LargeFileStorer.java

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,19 @@
99
import com.backblaze.b2.client.exceptions.B2Exception;
1010
import com.backblaze.b2.client.exceptions.B2LocalException;
1111
import com.backblaze.b2.client.structures.B2CopyPartRequest;
12+
import com.backblaze.b2.client.structures.B2FileSseForRequest;
1213
import com.backblaze.b2.client.structures.B2FileVersion;
1314
import com.backblaze.b2.client.structures.B2FinishLargeFileRequest;
1415
import com.backblaze.b2.client.structures.B2Part;
16+
import com.backblaze.b2.client.structures.B2StoreLargeFileRequest;
1517
import com.backblaze.b2.client.structures.B2UploadListener;
1618
import com.backblaze.b2.client.structures.B2UploadPartRequest;
1719
import com.backblaze.b2.client.structures.B2UploadPartUrlResponse;
1820
import com.backblaze.b2.client.structures.B2UploadProgress;
1921
import com.backblaze.b2.client.structures.B2UploadState;
2022
import com.backblaze.b2.util.B2ByteProgressListener;
2123
import com.backblaze.b2.util.B2ByteRange;
24+
import com.backblaze.b2.util.B2Preconditions;
2225

2326
import java.io.IOException;
2427
import java.util.ArrayList;
@@ -31,6 +34,8 @@
3134
import java.util.concurrent.Future;
3235
import java.util.function.Supplier;
3336

37+
import static com.backblaze.b2.client.structures.B2ServerSideEncryptionMode.SSE_C;
38+
3439
/**
3540
* A class for handling the creation of large files.
3641
*
@@ -45,6 +50,13 @@ public class B2LargeFileStorer {
4550
*/
4651
private final B2FileVersion fileVersion;
4752

53+
/**
54+
* The B2FileSseForRequest for the large file that is being created.
55+
* This contains the SSE-C parameters for SSE-C uploads and is null
56+
* otherwise.
57+
*/
58+
private final B2FileSseForRequest serverSideEncryptionOrNull;
59+
4860
/**
4961
* The parts that need to be stored before finishing the large file.
5062
*/
@@ -70,15 +82,17 @@ public class B2LargeFileStorer {
7082
private final ExecutorService executor;
7183

7284
B2LargeFileStorer(
73-
B2FileVersion fileVersion,
85+
B2StoreLargeFileRequest storeLargeFileRequest,
7486
List<B2PartStorer> partStorers,
7587
B2AccountAuthorizationCache accountAuthCache,
7688
B2StorageClientWebifier webifier,
7789
B2Retryer retryer,
7890
Supplier<B2RetryPolicy> retryPolicySupplier,
7991
ExecutorService executor) {
92+
B2Preconditions.checkArgumentIsNotNull(storeLargeFileRequest, "storeLargeFileRequest");
8093

81-
this.fileVersion = fileVersion;
94+
this.fileVersion = storeLargeFileRequest.getFileVersion();
95+
this.serverSideEncryptionOrNull = storeLargeFileRequest.getServerSideEncryption();
8296
this.partStorers = validateAndSortPartStorers(new ArrayList<>(partStorers));
8397
this.startingBytePositions = computeStartingBytePositions(partStorers);
8498

@@ -141,7 +155,6 @@ List<B2PartStorer> getPartStorers() {
141155
long getStartByteOrUnknown(int partNumber) {
142156
return startingBytePositions.get(partNumber - 1);
143157
}
144-
145158
public static B2LargeFileStorer forLocalContent(
146159
B2FileVersion largeFileVersion,
147160
B2ContentSource contentSource,
@@ -151,6 +164,27 @@ public static B2LargeFileStorer forLocalContent(
151164
B2Retryer retryer,
152165
Supplier<B2RetryPolicy> retryPolicySupplier,
153166
ExecutorService executor) throws B2Exception {
167+
return forLocalContent(
168+
B2StoreLargeFileRequest.builder(largeFileVersion).build(),
169+
contentSource,
170+
partSizes,
171+
accountAuthCache,
172+
webifier,
173+
retryer,
174+
retryPolicySupplier,
175+
executor);
176+
}
177+
178+
public static B2LargeFileStorer forLocalContent(
179+
B2StoreLargeFileRequest storeLargeFileRequest,
180+
B2ContentSource contentSource,
181+
B2PartSizes partSizes,
182+
B2AccountAuthorizationCache accountAuthCache,
183+
B2StorageClientWebifier webifier,
184+
B2Retryer retryer,
185+
Supplier<B2RetryPolicy> retryPolicySupplier,
186+
ExecutorService executor) throws B2Exception {
187+
B2Preconditions.checkArgumentIsNotNull(storeLargeFileRequest, "storeLargeFileRequest");
154188

155189
// Convert the contentSource into a list of B2PartStorer objects.
156190
final List<B2PartStorer> partContentSources = new ArrayList<>();
@@ -167,7 +201,7 @@ public static B2LargeFileStorer forLocalContent(
167201

168202
// Instantiate and return the manager.
169203
return new B2LargeFileStorer(
170-
largeFileVersion,
204+
storeLargeFileRequest,
171205
partContentSources,
172206
accountAuthCache,
173207
webifier,
@@ -395,6 +429,7 @@ B2Part uploadPart(
395429
new B2ContentSourceWithByteProgressListener(contentSource, progressListener);
396430
final B2UploadPartRequest uploadPartRequest = B2UploadPartRequest
397431
.builder(partNumber, contentSourceThatReportsProgress)
432+
.setServerSideEncryption(serverSideEncryptionOrNull)
398433
.build();
399434

400435
updateProgress(

core/src/main/java/com/backblaze/b2/client/B2LargeFileUploader.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
import com.backblaze.b2.client.contentSources.B2Headers;
1010
import com.backblaze.b2.client.exceptions.B2Exception;
1111
import com.backblaze.b2.client.exceptions.B2LocalException;
12+
import com.backblaze.b2.client.structures.B2FileSseForRequest;
1213
import com.backblaze.b2.client.structures.B2FileVersion;
1314
import com.backblaze.b2.client.structures.B2FinishLargeFileRequest;
1415
import com.backblaze.b2.client.structures.B2Part;
16+
import com.backblaze.b2.client.structures.B2ServerSideEncryptionMode;
1517
import com.backblaze.b2.client.structures.B2StartLargeFileRequest;
1618
import com.backblaze.b2.client.structures.B2UploadFileRequest;
1719
import com.backblaze.b2.client.structures.B2UploadListener;
@@ -134,6 +136,7 @@ B2FileVersion finishUploadingLargeFile(B2FileVersion largeFileVersion,
134136
// LARGE_FILE_SHA1 is a bit "special" since the SDK quietly adds it for the user.
135137
// we've checked LARGE_FILE_SHA1 above, so here, remove it and check any other entries against the request.
136138
final Map<String,String> infos = new TreeMap<>();
139+
//noinspection CollectionAddAllCanBeReplacedWithConstructor
137140
infos.putAll(largeFileVersion.getFileInfo());
138141
infos.remove(B2Headers.LARGE_FILE_SHA1);
139142
throwIfMismatch("fileInfo", toString(request.getFileInfo()), toString(infos));
@@ -287,8 +290,17 @@ private B2Part uploadOnePart(B2UploadPartUrlCache uploadPartUrlCache,
287290
}
288291
source = new B2ContentSourceWithByteProgressListener(source, progressListener);
289292

293+
// if original upload request includes SSE-C parameters, than we need to include those in
294+
// each uploadPart request as well
295+
final B2FileSseForRequest uploadFileSse = request.getServerSideEncryption();
296+
final B2FileSseForRequest uploadPartSse =
297+
(uploadFileSse != null && uploadFileSse.getMode().equals(B2ServerSideEncryptionMode.SSE_C))
298+
? uploadFileSse
299+
: null;
300+
290301
final B2UploadPartRequest partRequest = B2UploadPartRequest
291302
.builder(partSpec.partNumber, source)
303+
.setServerSideEncryption(uploadPartSse)
292304
.build();
293305

294306
final B2Part part = webifier.uploadPart(uploadPartUrlResponse, partRequest);

core/src/main/java/com/backblaze/b2/client/B2StorageClient.java

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,17 @@
3838
import com.backblaze.b2.client.structures.B2ListPartsRequest;
3939
import com.backblaze.b2.client.structures.B2ListUnfinishedLargeFilesRequest;
4040
import com.backblaze.b2.client.structures.B2StartLargeFileRequest;
41+
import com.backblaze.b2.client.structures.B2StoreLargeFileRequest;
4142
import com.backblaze.b2.client.structures.B2UpdateBucketRequest;
43+
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldRequest;
44+
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldResponse;
45+
import com.backblaze.b2.client.structures.B2UpdateFileRetentionRequest;
46+
import com.backblaze.b2.client.structures.B2UpdateFileRetentionResponse;
4247
import com.backblaze.b2.client.structures.B2UploadFileRequest;
4348
import com.backblaze.b2.client.structures.B2UploadListener;
4449
import com.backblaze.b2.client.structures.B2UploadPartUrlResponse;
4550
import com.backblaze.b2.client.structures.B2UploadUrlResponse;
51+
import com.backblaze.b2.util.B2Preconditions;
4652

4753
import java.io.Closeable;
4854
import java.util.List;
@@ -265,6 +271,37 @@ B2FileVersion storeLargeFileFromLocalContent(
265271
B2UploadListener uploadListenerOrNull,
266272
ExecutorService executor) throws B2Exception;
267273

274+
/**
275+
* Uploads the specified content source as separate parts to form a B2 large file,
276+
* optionally allowing caller to pass SSE-C parameters to match those given to
277+
* startLargeFile().
278+
*
279+
* This method assumes you have already called startLargeFile(). The return value
280+
* of that call needs to be passed into this method as part of a
281+
* B2StoreLargeFileRequest. However, this method will currently call finish file.
282+
*
283+
* XXX: should we switch to letting the caller finish the large file?
284+
*
285+
* @param storeLargeFileRequest The B2StoreLargeFileRequest for the large file
286+
* getting stored. This is built from the return
287+
* value of startLargeFile() and any other relevant
288+
* parameters.
289+
* @param contentSource The contentSource to upload.
290+
* @param uploadListenerOrNull The object that handles upload progress events.
291+
* This may be null if you do not need to be notified
292+
* of progress events.
293+
* @param executor The executor for uploading parts in parallel. The caller
294+
* retains ownership of the executor and is responsible for
295+
* shutting it down.
296+
* @return The fileVersion of the large file after it has been finished.
297+
* @throws B2Exception If there's trouble.
298+
*/
299+
B2FileVersion storeLargeFileFromLocalContent(
300+
B2StoreLargeFileRequest storeLargeFileRequest,
301+
B2ContentSource contentSource,
302+
B2UploadListener uploadListenerOrNull,
303+
ExecutorService executor) throws B2Exception;
304+
268305
/**
269306
* Initiates uploading the specified content source as separate parts to form a
270307
* B2 large file. This allows the upload to be cancelled partway through.
@@ -298,6 +335,41 @@ CompletableFuture<B2FileVersion> storeLargeFileFromLocalContentAsync(
298335
B2UploadListener uploadListenerOrNull,
299336
ExecutorService executor) throws B2Exception;
300337

338+
/**
339+
* Initiates uploading the specified content source as separate parts to form a
340+
* B2 large file. This allows the upload to be cancelled partway through.
341+
*
342+
* This method assumes you have already called startLargeFile(). The return value
343+
* of that call needs to be passed into this method.
344+
*
345+
* The returned future can be cancelled and this will also attempt to stop any part
346+
* uploads in progress.
347+
*
348+
* Cancelling after the b2_finish_large_file API call has been started will result in the
349+
* future being cancelled, but the API call can still succeed. There is no way to tell from
350+
* the future whether this is the case. The caller is responsible for checking and calling
351+
* B2StorageClient.cancelLargeFile.
352+
*
353+
* @param storeLargeFileRequest The B2StoreLargeFileRequest for the large file
354+
* getting stored. This is built from the return
355+
* value of startLargeFile() and any other relevant
356+
* parameters.
357+
* @param contentSource The contentSource to upload.
358+
* @param uploadListenerOrNull The object that handles upload progress events.
359+
* This may be null if you do not need to be notified
360+
* of progress events.
361+
* @param executor The executor for uploading parts in parallel. The caller
362+
* retains ownership of the executor and is responsible for
363+
* shutting it down.
364+
* @return CompletableFuture with the resulting B2FileVersion of the completed file
365+
* @throws B2Exception on error
366+
*/
367+
CompletableFuture<B2FileVersion> storeLargeFileFromLocalContentAsync(
368+
B2StoreLargeFileRequest storeLargeFileRequest,
369+
B2ContentSource contentSource,
370+
B2UploadListener uploadListenerOrNull,
371+
ExecutorService executor) throws B2Exception;
372+
301373
/**
302374
* Stores a large file, where storing each part may involve different behavior
303375
* or byte sources.
@@ -337,6 +409,47 @@ B2FileVersion storeLargeFile(
337409
B2UploadListener uploadListenerOrNull,
338410
ExecutorService executor) throws B2Exception;
339411

412+
/**
413+
* Stores a large file, where storing each part may involve different behavior
414+
* or byte sources, optionally allowing caller to pass SSE-C parameters to match
415+
* those given to startLargeFile().
416+
*
417+
* For example, this method supports the use case of making a copy of a file
418+
* that mostly has not changed, and the user only wishes to upload the parts
419+
* that have changed. In this case partStorers would be a mix of
420+
* B2CopyingPartStorers and one or more B2UploadingPartStorers.
421+
*
422+
* Another use case would be reattempting an upload of a large file where some
423+
* parts have completed, and some haven't. In this case, partStorers would
424+
* be a mix of B2AlreadyStoredPartStorer and B2UploadingPartStorers.
425+
*
426+
* This method assumes you have already called startLargeFile(). The return value
427+
* of that call needs to be passed into this method as part of a
428+
* B2StoreLargeFileRequest. However, this method will currently call finish file.
429+
* Note that each part, whether copied or uploaded,
430+
* is still subject to the minimum part size.
431+
*
432+
* @param storeLargeFileRequest The B2StoreLargeFileRequest for the large file
433+
* getting stored. This is built from the return
434+
* value of startLargeFile() and any other relevant
435+
* parameters.
436+
* @param partStorers The list of objects that know how to store the part
437+
* they are responsible for.
438+
* @param uploadListenerOrNull The object that handles upload progress events.
439+
* This may be null if you do not need to be notified
440+
* of progress events.
441+
* @param executor The executor for uploading parts in parallel. The caller
442+
* retains ownership of the executor and is responsible for
443+
* shutting it down.
444+
* @return The fileVersion of the large file after it has been finished.
445+
* @throws B2Exception If there's trouble.
446+
*/
447+
B2FileVersion storeLargeFile(
448+
B2StoreLargeFileRequest storeLargeFileRequest,
449+
List<B2PartStorer> partStorers,
450+
B2UploadListener uploadListenerOrNull,
451+
ExecutorService executor) throws B2Exception;
452+
340453
/**
341454
* Verifies that the given fileVersion represents an unfinished large file
342455
* and that the specified content is compatible-enough with the information
@@ -877,6 +990,25 @@ default String getDownloadByNameUrl(String bucketName,
877990
*/
878991
B2FileVersion finishLargeFile(B2FinishLargeFileRequest request) throws B2Exception;
879992

993+
/**
994+
* Updates the legal hold configuration of the specified file as described by the request.
995+
*
996+
* @param request specifies which file to update and how to update it.
997+
* @return the new state of the file
998+
* @throws B2Exception if there's any trouble.
999+
* @see <a href="https://www.backblaze.com/b2/docs/b2_update_file_legal_hold.html">b2_update_file_legal_hold</a>
1000+
*/
1001+
B2UpdateFileLegalHoldResponse updateFileLegalHold(B2UpdateFileLegalHoldRequest request) throws B2Exception;
1002+
1003+
/**
1004+
* Updates the file retention configuration of the specified file as described by the request.
1005+
*
1006+
* @param request specifies which file to update and how to update it.
1007+
* @return the new state of the file
1008+
* @throws B2Exception if there's any trouble.
1009+
* @see <a href="https://www.backblaze.com/b2/docs/b2_update_file_retention.html">b2_update_file_retention</a>
1010+
*/
1011+
B2UpdateFileRetentionResponse updateFileRetention(B2UpdateFileRetentionRequest request) throws B2Exception;
8801012

8811013
/**
8821014
* Closes this instance, releasing resources.

0 commit comments

Comments
 (0)