Skip to content

Commit

Permalink
DEV-7962: implement updateFileRetention (#55)
Browse files Browse the repository at this point in the history
* DEV-7962: implement updateFileRetention

* changes after review
  • Loading branch information
ericjding authored Mar 31, 2021
1 parent a8eda75 commit e887a33
Show file tree
Hide file tree
Showing 10 changed files with 393 additions and 0 deletions.
12 changes: 12 additions & 0 deletions core/src/main/java/com/backblaze/b2/client/B2StorageClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import com.backblaze.b2.client.structures.B2UpdateBucketRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldResponse;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionRequest;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionResponse;
import com.backblaze.b2.client.structures.B2UploadFileRequest;
import com.backblaze.b2.client.structures.B2UploadListener;
import com.backblaze.b2.client.structures.B2UploadPartUrlResponse;
Expand Down Expand Up @@ -929,6 +931,16 @@ default String getDownloadByNameUrl(String bucketName,
*/
B2UpdateFileLegalHoldResponse updateFileLegalHold(B2UpdateFileLegalHoldRequest request) throws B2Exception;

/**
* Updates the file retention configuration of the specified file as described by the request.
*
* @param request specifies which file to update and how to update it.
* @return the new state of the file
* @throws B2Exception if there's any trouble.
* @see <a href="https://www.backblaze.com/b2/docs/b2_update_file_retention.html">b2_update_file_retention</a>
*/
B2UpdateFileRetentionResponse updateFileRetention(B2UpdateFileRetentionRequest request) throws B2Exception;

/**
* Closes this instance, releasing resources.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
import com.backblaze.b2.client.structures.B2UpdateBucketRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldResponse;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionRequest;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionResponse;
import com.backblaze.b2.client.structures.B2UploadFileRequest;
import com.backblaze.b2.client.structures.B2UploadListener;
import com.backblaze.b2.client.structures.B2UploadPartUrlResponse;
Expand Down Expand Up @@ -169,6 +171,7 @@ public B2CreatedApplicationKey createKey(B2CreateKeyRequest request) throws B2Ex
);
}

@SuppressWarnings("RedundantThrows")
@Override
public B2ListKeysIterable applicationKeys(B2ListKeysRequest request) throws B2Exception {
return new B2ListKeysIterable(this, request);
Expand Down Expand Up @@ -324,11 +327,13 @@ private long getContentLength(B2ContentSource contentSource) throws B2LocalExcep

}

@SuppressWarnings("RedundantThrows")
@Override
public B2ListFilesIterable fileVersions(B2ListFileVersionsRequest request) throws B2Exception {
return new B2ListFileVersionsIterable(this, request);
}

@SuppressWarnings("RedundantThrows")
@Override
public B2ListFilesIterable fileNames(B2ListFileNamesRequest request) throws B2Exception {
return new B2ListFileNamesIterable(this, request);
Expand Down Expand Up @@ -501,6 +506,14 @@ public B2UpdateFileLegalHoldResponse updateFileLegalHold(B2UpdateFileLegalHoldRe
retryPolicySupplier.get());
}

@Override
public B2UpdateFileRetentionResponse updateFileRetention(B2UpdateFileRetentionRequest request) throws B2Exception {
return retryer.doRetry("b2_update_file_retention", accountAuthCache,
() -> webifier.updateFileRetention(accountAuthCache.get(), request),
retryPolicySupplier.get());
}


//
// For use by our iterators
// XXX: make private somehow, or move to B2StorageClient interface.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
import com.backblaze.b2.client.structures.B2UpdateBucketRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldResponse;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionRequest;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionResponse;
import com.backblaze.b2.client.structures.B2UploadFileRequest;
import com.backblaze.b2.client.structures.B2UploadPartRequest;
import com.backblaze.b2.client.structures.B2UploadPartUrlResponse;
Expand Down Expand Up @@ -171,6 +173,9 @@ String getDownloadByNameUrl(B2AccountAuthorization accountAuth,
B2UpdateFileLegalHoldResponse updateFileLegalHold(B2AccountAuthorization accountAuth,
B2UpdateFileLegalHoldRequest request) throws B2Exception;

B2UpdateFileRetentionResponse updateFileRetention(B2AccountAuthorization accountAuth,
B2UpdateFileRetentionRequest request) throws B2Exception;

/**
* Closes this object and its underlying resources.
* This is overridden from AutoCloseable to declare that it can't throw any exception.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
import com.backblaze.b2.client.structures.B2UpdateBucketRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldResponse;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionRequest;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionResponse;
import com.backblaze.b2.client.structures.B2UploadFileRequest;
import com.backblaze.b2.client.structures.B2UploadListener;
import com.backblaze.b2.client.structures.B2UploadPartRequest;
Expand Down Expand Up @@ -656,6 +658,16 @@ public B2UpdateFileLegalHoldResponse updateFileLegalHold(B2AccountAuthorization
B2UpdateFileLegalHoldResponse.class);
}

@Override
public B2UpdateFileRetentionResponse updateFileRetention(B2AccountAuthorization accountAuth,
B2UpdateFileRetentionRequest request) throws B2Exception {
return webApiClient.postJsonReturnJson(
makeUrl(accountAuth, "b2_update_file_retention"),
makeHeaders(accountAuth),
request,
B2UpdateFileRetentionResponse.class);
}

private void addAuthHeader(B2HeadersImpl.Builder builder,
B2AccountAuthorization accountAuth) {
builder.set(B2Headers.AUTHORIZATION, accountAuth.getAuthorizationToken());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class B2FileRetention {
@B2Json.optional
private final Long retainUntilTimestamp;

/**
* static field for convenience to use with updateFileRetention() to turn off retention
*/
public static final B2FileRetention NONE = new B2FileRetention(null, null);

@B2Json.constructor(params = "mode, retainUntilTimestamp")
public B2FileRetention(String mode, Long retainUntilTimestamp) {
this.mode = mode;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright 2021, Backblaze Inc. All Rights Reserved.
* License https://www.backblaze.com/using_b2_code.html
*/
package com.backblaze.b2.client.structures;

import com.backblaze.b2.json.B2Json;
import com.backblaze.b2.util.B2Preconditions;

import java.util.Objects;

public class B2UpdateFileRetentionRequest {
@B2Json.required
public final String fileName;

@B2Json.required
public final String fileId;

@B2Json.optional
public final boolean bypassGovernance;

@B2Json.required
public final B2FileRetention fileRetention;

@B2Json.constructor(params = "fileName, fileId, bypassGovernance, fileRetention")
private B2UpdateFileRetentionRequest(String fileName,
String fileId,
boolean bypassGovernance,
B2FileRetention fileRetention) {
// perform some simple validation checks:
// 1) make sure mode is valid (i.e., if non-null, then either governance or compliance)
B2Preconditions.checkArgument(fileRetention.getMode() == null ||
B2FileRetentionMode.COMPLIANCE.equals(fileRetention.getMode()) ||
B2FileRetentionMode.GOVERNANCE.equals(fileRetention.getMode()),
"Invalid value for file retention mode");
// 2) Both mode and retainUntilTimestamp must be either null or non-null
B2Preconditions.checkArgument(
(fileRetention.getMode() != null && fileRetention.getRetainUntilTimestamp() != null) ||
(fileRetention.getMode() == null && fileRetention.getRetainUntilTimestamp() == null),
"Both file retention mode and retainUntilTimestamp are required if either is supplied");

this.fileName = fileName;
this.fileId = fileId;
this.bypassGovernance = bypassGovernance;
this.fileRetention = fileRetention;
}

public String getFileName() {
return fileName;
}

public String getFileId() {
return fileId;
}

public boolean isBypassGovernance() {
return bypassGovernance;
}

public B2FileRetention getFileRetention() {
return fileRetention;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
B2UpdateFileRetentionRequest that = (B2UpdateFileRetentionRequest) o;
return Objects.equals(getFileName(), that.getFileName()) &&
Objects.equals(getFileId(), that.getFileId()) &&
isBypassGovernance() == that.isBypassGovernance() &&
Objects.equals(getFileRetention(), that.getFileRetention());
}

@Override
public int hashCode() {
return Objects.hash(getFileName(), getFileId(), isBypassGovernance(), getFileRetention());
}

public static Builder builder(String fileName,
String fileId,
B2FileRetention fileRetention) {
return new Builder(fileName, fileId, fileRetention);
}

public static class Builder {
private final String fileName;
private final String fileId;
private final B2FileRetention fileRetention;

private boolean bypassGovernance;

public Builder(String fileName,
String fileId,
B2FileRetention fileRetention) {
this.fileName = fileName;
this.fileId = fileId;
this.fileRetention = fileRetention;
}

public Builder setBypassGovernance(boolean bypassGovernance) {
this.bypassGovernance = bypassGovernance;
return this;
}

public B2UpdateFileRetentionRequest build() {
return new B2UpdateFileRetentionRequest(
fileName,
fileId,
bypassGovernance,
fileRetention);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2021, Backblaze Inc. All Rights Reserved.
* License https://www.backblaze.com/using_b2_code.html
*/
package com.backblaze.b2.client.structures;

import com.backblaze.b2.json.B2Json;

import java.util.Objects;

public class B2UpdateFileRetentionResponse {
@B2Json.required
public final String fileName;

@B2Json.required
public final String fileId;

@B2Json.required
public final B2FileRetention fileRetention;

@B2Json.constructor(params = "fileName, fileId, fileRetention")
public B2UpdateFileRetentionResponse(String fileName,
String fileId,
B2FileRetention fileRetention) {
this.fileName = fileName;
this.fileId = fileId;
this.fileRetention = fileRetention;
}

public String getFileName() {
return fileName;
}

public String getFileId() {
return fileId;
}

public B2FileRetention getFileRetention() {
return fileRetention;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
B2UpdateFileRetentionResponse that = (B2UpdateFileRetentionResponse) o;
return Objects.equals(getFileName(), that.getFileName()) &&
Objects.equals(getFileId(), that.getFileId()) &&
Objects.equals(getFileRetention(), that.getFileRetention());
}

@Override
public int hashCode() {
return Objects.hash(getFileName(), getFileId(), getFileRetention());
}

@Override
public String toString() {
return "B2UpdateFileLegalHoldResponse {" +
"fileId='" + fileId + '\'' +
", fileName='" + fileName + '\'' +
", fileRetention='" + fileRetention + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import com.backblaze.b2.client.structures.B2DownloadAuthorization;
import com.backblaze.b2.client.structures.B2DownloadByIdRequest;
import com.backblaze.b2.client.structures.B2DownloadByNameRequest;
import com.backblaze.b2.client.structures.B2FileRetention;
import com.backblaze.b2.client.structures.B2FileRetentionMode;
import com.backblaze.b2.client.structures.B2FileVersion;
import com.backblaze.b2.client.structures.B2FinishLargeFileRequest;
import com.backblaze.b2.client.structures.B2GetDownloadAuthorizationRequest;
Expand All @@ -52,6 +54,8 @@
import com.backblaze.b2.client.structures.B2UpdateBucketRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldResponse;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionRequest;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionResponse;
import com.backblaze.b2.client.structures.B2UploadFileRequest;
import com.backblaze.b2.client.structures.B2UploadListener;
import com.backblaze.b2.client.structures.B2UploadPartRequest;
Expand Down Expand Up @@ -1062,6 +1066,22 @@ public void testUpdateFileLegalHold() throws B2Exception {
verify(webifier, times(1)).updateFileLegalHold(any(), eq(request));
}

@Test
public void testUpdateFileRetention() throws B2Exception {
final B2FileRetention fileRetention = new B2FileRetention(B2FileRetentionMode.COMPLIANCE, 10000L);
final B2UpdateFileRetentionRequest request = B2UpdateFileRetentionRequest
.builder(fileName(1), fileId(1), fileRetention)
.build();
final B2UpdateFileRetentionResponse response =
new B2UpdateFileRetentionResponse(fileName(1), fileId(1), fileRetention);
when(webifier.updateFileRetention(any(), eq(request))).thenReturn(response);

assertSame(response, client.updateFileRetention(request));

verify(webifier, times(1)).authorizeAccount(any());
verify(webifier, times(1)).updateFileRetention(any(), eq(request));
}

@Test
public void testClose() {
final B2AccountAuthorizer authorizer = mock(B2AccountAuthorizer.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.backblaze.b2.client.structures.B2TestMode;
import com.backblaze.b2.client.structures.B2UpdateBucketRequest;
import com.backblaze.b2.client.structures.B2UpdateFileLegalHoldRequest;
import com.backblaze.b2.client.structures.B2UpdateFileRetentionRequest;
import com.backblaze.b2.client.structures.B2UploadFileRequest;
import com.backblaze.b2.client.structures.B2UploadListener;
import com.backblaze.b2.client.structures.B2UploadPartRequest;
Expand Down Expand Up @@ -1880,6 +1881,38 @@ public void testUpdateFileLegalHold() throws B2Exception {
checkRequestCategory(OTHER, w -> w.updateFileLegalHold(ACCOUNT_AUTH, requestReal));
}

@Test
public void testUpdateFileRetention() throws B2Exception {
final B2FileRetention fileRetention = new B2FileRetention(B2FileRetentionMode.COMPLIANCE, 10000L);
final B2UpdateFileRetentionRequest requestReal = B2UpdateFileRetentionRequest
.builder(fileName(1), fileId(1), fileRetention)
.build();
webifier.updateFileRetention(ACCOUNT_AUTH, requestReal);

webApiClient.check("postJsonReturnJson.\n" +
"url:\n" +
" apiUrl1/b2api/v2/b2_update_file_retention\n" +
"headers:\n" +
" Authorization: accountToken1\n" +
" User-Agent: SecretAgentMan/3.19.28\n" +
" X-Bz-Test-Mode: force_cap_exceeded\n" +
"request:\n" +
" {\n" +
" \"bypassGovernance\": false,\n" +
" \"fileId\": \"4_zBlah_0000001\",\n" +
" \"fileName\": \"files/\u81ea\u7531/0001\",\n" +
" \"fileRetention\": {\n" +
" \"mode\": \"compliance\",\n" +
" \"retainUntilTimestamp\": 10000\n" +
" }\n" +
" }\n" +
"responseClass:\n" +
" B2UpdateFileRetentionResponse\n"
);

checkRequestCategory(OTHER, w -> w.updateFileRetention(ACCOUNT_AUTH, requestReal));
}

@Test
public void testTestModes() throws B2Exception {
// test each possible testMode, including "none".
Expand Down
Loading

0 comments on commit e887a33

Please sign in to comment.