Skip to content

Commit

Permalink
feat: add object retention feature (#2277)
Browse files Browse the repository at this point in the history
* feat: add object retention feature

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* address review comments

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* Add a workaround to avoid a testbench failure

* chore: some fixes from pairing with jesse

* chore: put a `!` :don't program while sleepy:

* chore: mvn-fmt

* add a way to avoid using the objectRetentionField in bucket tests

* add retention to blobfield tests

* clirr and fmt

* add todos

* fmt

---------

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Co-authored-by: BenWhitehead <BenWhitehead@users.noreply.github.com>
  • Loading branch information
3 people committed Nov 30, 2023
1 parent 6d26d14 commit 3deb29b
Show file tree
Hide file tree
Showing 19 changed files with 548 additions and 21 deletions.
6 changes: 6 additions & 0 deletions google-cloud-storage/clirr-ignored-differences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
<method>* writeAndClose(*)</method>
</difference>

<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/storage/BlobInfo$Builder</className>
<method>com.google.cloud.storage.BlobInfo$Builder setRetention(com.google.cloud.storage.BlobInfo$Retention)</method>
</difference>

<!-- @BetaApi members -->
<difference>
<differenceType>7009</differenceType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,12 @@ Builder setRetentionExpirationTimeOffsetDateTime(OffsetDateTime retentionExpirat
return this;
}

@Override
public Builder setRetention(Retention retention) {
infoBuilder.setRetention(retention);
return this;
}

@Override
public Blob build() {
return new Blob(storage, infoBuilder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.api.client.util.Data;
import com.google.api.core.ApiFunction;
import com.google.api.core.BetaApi;
import com.google.cloud.StringEnumType;
import com.google.cloud.StringEnumValue;
import com.google.cloud.storage.Storage.BlobField;
import com.google.cloud.storage.TransportCompatibility.Transport;
import com.google.cloud.storage.UnifiedOpts.NamedField;
Expand Down Expand Up @@ -104,6 +107,7 @@ public class BlobInfo implements Serializable {
private final Boolean eventBasedHold;
private final Boolean temporaryHold;
private final OffsetDateTime retentionExpirationTime;
private final Retention retention;
private final transient ImmutableSet<NamedField> modifiedFields;

/** This class is meant for internal use only. Users are discouraged from using this class. */
Expand Down Expand Up @@ -168,6 +172,119 @@ public final boolean equals(Object o) {
}
}

/**
* Defines a blob's Retention policy. Can only be used on objects in a retention-enabled bucket.
*/
public static final class Retention implements Serializable {

private static final long serialVersionUID = 5046718464542688444L;

private Mode mode;

private OffsetDateTime retainUntilTime;

/** Returns the retention policy's Mode. Can be Locked or Unlocked. */
public Mode getMode() {
return mode;
}

/** Returns what time this object will be retained until, if the mode is Locked. */
public OffsetDateTime getRetainUntilTime() {
return retainUntilTime;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Retention)) {
return false;
}
Retention that = (Retention) o;
return Objects.equals(mode, that.mode)
&& Objects.equals(retainUntilTime, that.retainUntilTime);
}

@Override
public int hashCode() {
return Objects.hash(mode, retainUntilTime);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("mode", mode)
.add("retainUntilTime", retainUntilTime)
.toString();
}

public static Builder newBuilder() {
return new Builder();
}

public Builder toBuilder() {
return new Builder().setMode(this.mode).setRetainUntilTime(this.retainUntilTime);
}

private Retention() {}

public Retention(Builder builder) {
this.mode = builder.mode;
this.retainUntilTime = builder.retainUntilTime;
}

public static final class Builder {
private Mode mode;
private OffsetDateTime retainUntilTime;

/** Sets the retention policy's Mode. Can be Locked or Unlocked. */
public Builder setMode(Mode mode) {
this.mode = mode;
return this;
}

/** Sets what time this object will be retained until, if the mode is Locked. */
public Builder setRetainUntilTime(OffsetDateTime retainUntilTime) {
this.retainUntilTime = retainUntilTime;
return this;
}

public Retention build() {
return new Retention(this);
}
}

public static final class Mode extends StringEnumValue {
private static final long serialVersionUID = 1973143582659557184L;

private Mode(String constant) {
super(constant);
}

private static final ApiFunction<String, Mode> CONSTRUCTOR = Mode::new;

private static final StringEnumType<Mode> type =
new StringEnumType<>(Mode.class, CONSTRUCTOR);

public static final Mode UNLOCKED = type.createAndRegister("Unlocked");

public static final Mode LOCKED = type.createAndRegister("Locked");

public static Mode valueOfStrict(String constant) {
return type.valueOfStrict(constant);
}

public static Mode valueOf(String constant) {
return type.valueOf(constant);
}

public static Mode[] values() {
return type.values();
}
}
}

/** Builder for {@code BlobInfo}. */
public abstract static class Builder {

Expand Down Expand Up @@ -408,6 +525,8 @@ Builder setRetentionExpirationTimeOffsetDateTime(OffsetDateTime retentionExpirat
return setRetentionExpirationTime(millisOffsetDateTimeCodec.decode(retentionExpirationTime));
}

public abstract Builder setRetention(Retention retention);

/** Creates a {@code BlobInfo} object. */
public abstract BlobInfo build();

Expand Down Expand Up @@ -506,6 +625,7 @@ static final class BuilderImpl extends Builder {
private Boolean eventBasedHold;
private Boolean temporaryHold;
private OffsetDateTime retentionExpirationTime;
private Retention retention;
private final ImmutableSet.Builder<NamedField> modifiedFields = ImmutableSet.builder();

BuilderImpl(BlobId blobId) {
Expand Down Expand Up @@ -543,6 +663,7 @@ static final class BuilderImpl extends Builder {
eventBasedHold = blobInfo.eventBasedHold;
temporaryHold = blobInfo.temporaryHold;
retentionExpirationTime = blobInfo.retentionExpirationTime;
retention = blobInfo.retention;
}

@Override
Expand Down Expand Up @@ -916,6 +1037,14 @@ Builder setRetentionExpirationTimeOffsetDateTime(OffsetDateTime retentionExpirat
return this;
}

@Override
public Builder setRetention(Retention retention) {
// todo: b/308194853
modifiedFields.add(BlobField.RETENTION);
this.retention = retention;
return this;
}

@Override
public BlobInfo build() {
checkNotNull(blobId);
Expand Down Expand Up @@ -1139,6 +1268,7 @@ Builder clearRetentionExpirationTime() {
eventBasedHold = builder.eventBasedHold;
temporaryHold = builder.temporaryHold;
retentionExpirationTime = builder.retentionExpirationTime;
retention = builder.retention;
modifiedFields = builder.modifiedFields.build();
}

Expand Down Expand Up @@ -1532,6 +1662,11 @@ public OffsetDateTime getRetentionExpirationTimeOffsetDateTime() {
return retentionExpirationTime;
}

/** Returns the object's Retention policy. */
public Retention getRetention() {
return retention;
}

/** Returns a builder for the current blob. */
public Builder toBuilder() {
return new BuilderImpl(this);
Expand Down Expand Up @@ -1581,6 +1716,7 @@ public int hashCode() {
kmsKeyName,
eventBasedHold,
temporaryHold,
retention,
retentionExpirationTime);
}

Expand Down Expand Up @@ -1622,7 +1758,8 @@ public boolean equals(Object o) {
&& Objects.equals(kmsKeyName, blobInfo.kmsKeyName)
&& Objects.equals(eventBasedHold, blobInfo.eventBasedHold)
&& Objects.equals(temporaryHold, blobInfo.temporaryHold)
&& Objects.equals(retentionExpirationTime, blobInfo.retentionExpirationTime);
&& Objects.equals(retentionExpirationTime, blobInfo.retentionExpirationTime)
&& Objects.equals(retention, blobInfo.retention);
}

ImmutableSet<NamedField> getModifiedFields() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,16 @@ public static BlobTargetOption userProject(@NonNull String userProject) {
return new BlobTargetOption(UnifiedOpts.userProject(userProject));
}

/**
* Returns an option for overriding an Unlocked Retention policy. This must be set to true in
* order to change a policy from Unlocked to Locked, to set it to null, or to reduce its
* retainUntilTime attribute.
*/
@TransportCompatibility({Transport.HTTP})
public static BlobTargetOption overrideUnlockedRetention(boolean overrideUnlockedRetention) {
return new BlobTargetOption(UnifiedOpts.overrideUnlockedRetention(overrideUnlockedRetention));
}

/**
* Deduplicate any options which are the same parameter. The value which comes last in {@code
* os} will be the value included in the return.
Expand Down Expand Up @@ -732,6 +742,12 @@ public Builder setCustomPlacementConfig(CustomPlacementConfig customPlacementCon
return this;
}

@Override
Builder setObjectRetention(ObjectRetention objectRetention) {
infoBuilder.setObjectRetention(objectRetention);
return this;
}

@Override
public Bucket build() {
return new Bucket(storage, infoBuilder);
Expand Down
Loading

0 comments on commit 3deb29b

Please sign in to comment.