getMetadata() {
return metadata == null || Data.isNull(metadata) ? null : Collections.unmodifiableMap(metadata);
}
- /**
- * Returns blob's data generation. Used for blob versioning.
- */
+ /** Returns blob's data generation. Used for blob versioning. */
public Long getGeneration() {
return getBlobId().getGeneration();
}
/**
- * Returns blob's metageneration. Used for preconditions and for detecting changes in metadata.
- * A metageneration number is only meaningful in the context of a particular generation of a
+ * Returns blob's metageneration. Used for preconditions and for detecting changes in metadata. A
+ * metageneration number is only meaningful in the context of a particular generation of a
* particular blob.
*/
public Long getMetageneration() {
return metageneration;
}
- /**
- * Returns the deletion time of the blob.
- */
+ /** Returns the deletion time of the blob. */
public Long getDeleteTime() {
return deleteTime;
}
- /**
- * Returns the last modification time of the blob's metadata.
- */
+ /** Returns the last modification time of the blob's metadata. */
public Long getUpdateTime() {
return updateTime;
}
- /**
- * Returns the creation time of the blob.
- */
+ /** Returns the creation time of the blob. */
public Long getCreateTime() {
return createTime;
}
/**
* Returns {@code true} if the current blob represents a directory. This can only happen if the
- * blob is returned by {@link Storage#list(String, Storage.BlobListOption...)} when the
- * {@link Storage.BlobListOption#currentDirectory()} option is used. When this is the case only
- * {@link #getBlobId()} and {@link #getSize()} are set for the current blob:
- * {@link BlobId#getName()} ends with the '/' character, {@link BlobId#getGeneration()} returns
- * {@code null} and {@link #getSize()} is {@code 0}.
+ * blob is returned by {@link Storage#list(String, Storage.BlobListOption...)} when the {@link
+ * Storage.BlobListOption#currentDirectory()} option is used. When this is the case only {@link
+ * #getBlobId()} and {@link #getSize()} are set for the current blob: {@link BlobId#getName()}
+ * ends with the '/' character, {@link BlobId#getGeneration()} returns {@code null} and {@link
+ * #getSize()} is {@code 0}.
*/
public boolean isDirectory() {
return isDirectory;
@@ -785,44 +743,77 @@ public CustomerEncryption getCustomerEncryption() {
return customerEncryption;
}
- /**
- * Returns the storage class of the blob.
- */
+ /** Returns the storage class of the blob. */
public StorageClass getStorageClass() {
return storageClass;
}
- /**
- * Returns the Cloud KMS key used to encrypt the blob, if any.
- */
+ /** Returns the Cloud KMS key used to encrypt the blob, if any. */
public String getKmsKeyName() {
return kmsKeyName;
}
/**
- * Returns the event based hold status of the blob, if any.
+ * Returns a {@code Boolean} with either {@code true}, {@code null} and in certain cases {@code
+ * false}.
+ *
+ * Case 1: {@code true} the field {@link
+ * com.google.cloud.storage.Storage.BlobField#EVENT_BASED_HOLD} is selected in a {@link
+ * Storage#get(BlobId, Storage.BlobGetOption...)} and event-based hold for the blob is enabled.
+ *
+ *
Case 2.1: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BlobField#EVENT_BASED_HOLD} is selected in a {@link
+ * Storage#get(BlobId, Storage.BlobGetOption...)}, but event-based hold for the blob is not
+ * enabled. This case can be considered implicitly {@code false}.
+ *
+ *
Case 2.2: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BlobField#EVENT_BASED_HOLD} is not selected in a {@link
+ * Storage#get(BlobId, Storage.BlobGetOption...)}, and the state for this field is unknown.
+ *
+ *
Case 3: {@code false} event-based hold is explicitly set to false using in a {@link
+ * Builder#setEventBasedHold(Boolean)} client side for a follow-up request e.g. {@link
+ * Storage#update(BlobInfo, Storage.BlobTargetOption...)} in which case the value of event-based
+ * hold will remain {@code false} for the given instance.
*/
public Boolean getEventBasedHold() {
- return eventBasedHold;
+ return Data.isNull(eventBasedHold) ? null : eventBasedHold;
}
/**
- * Returns the temporary hold status of the blob, if any.
+ * Returns a {@code Boolean} with either {@code true}, {@code null} and in certain cases {@code
+ * false}.
+ *
+ * Case 1: {@code true} the field {@link
+ * com.google.cloud.storage.Storage.BlobField#TEMPORARY_HOLD} is selected in a {@link
+ * Storage#get(BlobId, Storage.BlobGetOption...)} and temporary hold for the blob is enabled.
+ *
+ *
Case 2.1: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BlobField#TEMPORARY_HOLD} is selected in a {@link
+ * Storage#get(BlobId, Storage.BlobGetOption...)}, but temporary hold for the blob is not enabled.
+ * This case can be considered implicitly {@code false}.
+ *
+ *
Case 2.2: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BlobField#TEMPORARY_HOLD} is not selected in a {@link
+ * Storage#get(BlobId, Storage.BlobGetOption...)}, and the state for this field is unknown.
+ *
+ *
Case 3: {@code false} event-based hold is explicitly set to false using in a {@link
+ * Builder#setEventBasedHold(Boolean)} client side for a follow-up request e.g. {@link
+ * Storage#update(BlobInfo, Storage.BlobTargetOption...)} in which case the value of temporary
+ * hold will remain {@code false} for the given instance.
*/
public Boolean getTemporaryHold() {
- return temporaryHold;
+ return Data.isNull(temporaryHold) ? null : temporaryHold;
}
/**
- * Returns the retention expiration time of the blob, if a retention period is defined.
+ * Returns the retention expiration time of the blob as {@code Long}, if a retention period is
+ * defined. If retention period is not defined this value returns {@code null}
*/
public Long getRetentionExpirationTime() {
- return retentionExpirationTime;
+ return Data.isNull(retentionExpirationTime) ? null : retentionExpirationTime;
}
- /**
- * Returns a builder for the current blob.
- */
+ /** Returns a builder for the current blob. */
public Builder toBuilder() {
return new BuilderImpl(this);
}
@@ -848,19 +839,22 @@ public int hashCode() {
public boolean equals(Object obj) {
return obj == this
|| obj != null
- && obj.getClass().equals(BlobInfo.class)
- && Objects.equals(toPb(), ((BlobInfo) obj).toPb());
+ && obj.getClass().equals(BlobInfo.class)
+ && Objects.equals(toPb(), ((BlobInfo) obj).toPb());
}
StorageObject toPb() {
StorageObject storageObject = blobId.toPb();
if (acl != null) {
- storageObject.setAcl(Lists.transform(acl, new Function() {
- @Override
- public ObjectAccessControl apply(Acl acl) {
- return acl.toObjectPb();
- }
- }));
+ storageObject.setAcl(
+ Lists.transform(
+ acl,
+ new Function() {
+ @Override
+ public ObjectAccessControl apply(Acl acl) {
+ return acl.toObjectPb();
+ }
+ }));
}
if (deleteTime != null) {
storageObject.setTimeDeleted(new DateTime(deleteTime));
@@ -885,8 +879,8 @@ public ObjectAccessControl apply(Acl acl) {
if (metadata != null && !Data.isNull(metadata)) {
pbMetadata = Maps.newHashMapWithExpectedSize(metadata.size());
for (Map.Entry entry : metadata.entrySet()) {
- pbMetadata.put(entry.getKey(),
- firstNonNull(entry.getValue(), Data.nullOf(String.class)));
+ pbMetadata.put(
+ entry.getKey(), firstNonNull(entry.getValue(), Data.nullOf(String.class)));
}
}
if (customerEncryption != null) {
@@ -916,37 +910,27 @@ public ObjectAccessControl apply(Acl acl) {
return storageObject;
}
- /**
- * Returns a {@code BlobInfo} builder where blob identity is set using the provided values.
- */
+ /** Returns a {@code BlobInfo} builder where blob identity is set using the provided values. */
public static Builder newBuilder(BucketInfo bucketInfo, String name) {
return newBuilder(bucketInfo.getName(), name);
}
- /**
- * Returns a {@code BlobInfo} builder where blob identity is set using the provided values.
- */
+ /** Returns a {@code BlobInfo} builder where blob identity is set using the provided values. */
public static Builder newBuilder(String bucket, String name) {
return newBuilder(BlobId.of(bucket, name));
}
- /**
- * Returns a {@code BlobInfo} builder where blob identity is set using the provided values.
- */
+ /** Returns a {@code BlobInfo} builder where blob identity is set using the provided values. */
public static Builder newBuilder(BucketInfo bucketInfo, String name, Long generation) {
return newBuilder(bucketInfo.getName(), name, generation);
}
- /**
- * Returns a {@code BlobInfo} builder where blob identity is set using the provided values.
- */
+ /** Returns a {@code BlobInfo} builder where blob identity is set using the provided values. */
public static Builder newBuilder(String bucket, String name, Long generation) {
return newBuilder(BlobId.of(bucket, name, generation));
}
- /**
- * Returns a {@code BlobInfo} builder where blob identity is set using the provided value.
- */
+ /** Returns a {@code BlobInfo} builder where blob identity is set using the provided value. */
public static Builder newBuilder(BlobId blobId) {
return new BuilderImpl(blobId);
}
@@ -1011,13 +995,15 @@ static BlobInfo fromPb(StorageObject storageObject) {
builder.setOwner(Acl.Entity.fromPb(storageObject.getOwner().getEntity()));
}
if (storageObject.getAcl() != null) {
- builder.setAcl(Lists.transform(storageObject.getAcl(),
- new Function() {
- @Override
- public Acl apply(ObjectAccessControl objectAccessControl) {
- return Acl.fromPb(objectAccessControl);
- }
- }));
+ builder.setAcl(
+ Lists.transform(
+ storageObject.getAcl(),
+ new Function() {
+ @Override
+ public Acl apply(ObjectAccessControl objectAccessControl) {
+ return Acl.fromPb(objectAccessControl);
+ }
+ }));
}
if (storageObject.containsKey("isDirectory")) {
builder.setIsDirectory(Boolean.TRUE);
diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
index e24a5a7a89eb..0c417a8aee0d 100644
--- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
+++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
@@ -50,7 +50,7 @@
* Google Storage bucket metadata;
*
* @see Concepts and
- * Terminology
+ * Terminology
*/
public class BucketInfo implements Serializable {
@@ -106,7 +106,11 @@ public abstract static class DeleteRule implements Serializable {
private final Type type;
public enum Type {
- AGE, CREATE_BEFORE, NUM_NEWER_VERSIONS, IS_LIVE, UNKNOWN
+ AGE,
+ CREATE_BEFORE,
+ NUM_NEWER_VERSIONS,
+ IS_LIVE,
+ UNKNOWN
}
DeleteRule(Type type) {
@@ -183,8 +187,8 @@ public static class AgeDeleteRule extends DeleteRule {
* Creates an {@code AgeDeleteRule} object.
*
* @param daysToLive blobs' Time To Live expressed in days. The time when the age condition is
- * considered to be satisfied is computed by adding {@code daysToLive} days to the
- * midnight following blob's creation time in UTC.
+ * considered to be satisfied is computed by adding {@code daysToLive} days to the midnight
+ * following blob's creation time in UTC.
*/
public AgeDeleteRule(int daysToLive) {
super(Type.AGE);
@@ -222,8 +226,7 @@ private void writeObject(ObjectOutputStream out) throws IOException {
out.writeUTF(rule.toString());
}
- private void readObject(ObjectInputStream in) throws IOException,
- ClassNotFoundException {
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
rule = new JacksonFactory().fromString(in.readUTF(), Rule.class);
}
@@ -310,8 +313,8 @@ public static class IsLiveDeleteRule extends DeleteRule {
/**
* Creates an {@code IsLiveDeleteRule} object.
*
- * @param isLive if set to {@code true} live blobs meet the delete condition. If set to
- * {@code false} delete condition is met by archived blobs.
+ * @param isLive if set to {@code true} live blobs meet the delete condition. If set to {@code
+ * false} delete condition is met by archived blobs.
*/
public IsLiveDeleteRule(boolean isLive) {
super(Type.IS_LIVE);
@@ -328,16 +331,11 @@ void populateCondition(Rule.Condition condition) {
}
}
- /**
- * Builder for {@code BucketInfo}.
- */
+ /** Builder for {@code BucketInfo}. */
public abstract static class Builder {
- Builder() {
- }
+ Builder() {}
- /**
- * Sets the bucket's name.
- */
+ /** Sets the bucket's name. */
public abstract Builder setName(String name);
abstract Builder setGeneratedId(String generatedId);
@@ -347,9 +345,8 @@ public abstract static class Builder {
abstract Builder setSelfLink(String selfLink);
/**
- * Sets whether a user accessing the bucket or an object it contains should assume the transit costs
- * related to the access.
- *
+ * Sets whether a user accessing the bucket or an object it contains should assume the transit
+ * costs related to the access.
*/
public abstract Builder setRequesterPays(Boolean requesterPays);
@@ -365,9 +362,7 @@ public abstract static class Builder {
*/
public abstract Builder setIndexPage(String indexPage);
- /**
- * Sets the custom object to return when a requested resource is not found.
- */
+ /** Sets the custom object to return when a requested resource is not found. */
public abstract Builder setNotFoundPage(String notFoundPage);
/**
@@ -379,15 +374,15 @@ public abstract static class Builder {
/**
* Sets the bucket's storage class. This defines how blobs in the bucket are stored and
- * determines the SLA and the cost of storage. A list of supported values is available
- * here.
+ * determines the SLA and the cost of storage. A list of supported values is available here.
*/
public abstract Builder setStorageClass(StorageClass storageClass);
/**
* Sets the bucket's location. Data for blobs in the bucket resides in physical storage within
- * this region. A list of supported values is available
- * here.
+ * this region. A list of supported values is available here.
*/
public abstract Builder setLocation(String location);
@@ -400,8 +395,8 @@ public abstract static class Builder {
/**
* Sets the bucket's Cross-Origin Resource Sharing (CORS) configuration.
*
- * @see
- * Cross-Origin Resource Sharing (CORS)
+ * @see Cross-Origin Resource
+ * Sharing (CORS)
*/
public abstract Builder setCors(Iterable cors);
@@ -409,7 +404,7 @@ public abstract static class Builder {
* Sets the bucket's access control configuration.
*
* @see
+ * href="https://cloud.google.com/storage/docs/access-control#About-Access-Control-Lists">
* About Access Control Lists
*/
public abstract Builder setAcl(Iterable acl);
@@ -419,24 +414,18 @@ public abstract static class Builder {
* configuration is specified.
*
* @see
+ * href="https://cloud.google.com/storage/docs/access-control#About-Access-Control-Lists">
* About Access Control Lists
*/
public abstract Builder setDefaultAcl(Iterable acl);
- /**
- * Sets the label of this bucket.
- */
+ /** Sets the label of this bucket. */
public abstract Builder setLabels(Map labels);
- /**
- * Sets the default Cloud KMS key name for this bucket.
- */
+ /** Sets the default Cloud KMS key name for this bucket. */
public abstract Builder setDefaultKmsKeyName(String defaultKmsKeyName);
- /**
- * Sets the default event based hold for this bucket.
- */
+ /** Sets the default event-based hold for this bucket. */
public abstract Builder setDefaultEventBasedHold(Boolean defaultEventBasedHold);
abstract Builder setRetentionEffectiveTime(Long retentionEffectiveTime);
@@ -444,14 +433,12 @@ public abstract static class Builder {
abstract Builder setRetentionPolicyIsLocked(Boolean retentionPolicyIsLocked);
/**
- * If policy is not locked this value can be cleared, increased, and decreased.
- * If policy is locked the retention period can only be increased.
+ * If policy is not locked this value can be cleared, increased, and decreased. If policy is
+ * locked the retention period can only be increased.
*/
public abstract Builder setRetentionPeriod(Long retentionPeriod);
- /**
- * Creates a {@code BucketInfo} object.
- */
+ /** Creates a {@code BucketInfo} object. */
public abstract BucketInfo build();
}
@@ -621,26 +608,29 @@ public Builder setLabels(Map labels) {
@Override
public Builder setDefaultKmsKeyName(String defaultKmsKeyName) {
- this.defaultKmsKeyName = defaultKmsKeyName != null
- ? defaultKmsKeyName : Data.nullOf(String.class);
+ this.defaultKmsKeyName =
+ defaultKmsKeyName != null ? defaultKmsKeyName : Data.nullOf(String.class);
return this;
}
@Override
public Builder setDefaultEventBasedHold(Boolean defaultEventBasedHold) {
- this.defaultEventBasedHold = firstNonNull(defaultEventBasedHold, Data.nullOf(Boolean.class));
+ this.defaultEventBasedHold =
+ firstNonNull(defaultEventBasedHold, Data.nullOf(Boolean.class));
return this;
}
@Override
Builder setRetentionEffectiveTime(Long retentionEffectiveTime) {
- this.retentionEffectiveTime = firstNonNull(retentionEffectiveTime, Data.nullOf(Long.class));
+ this.retentionEffectiveTime =
+ firstNonNull(retentionEffectiveTime, Data.nullOf(Long.class));
return this;
}
@Override
Builder setRetentionPolicyIsLocked(Boolean retentionPolicyIsLocked) {
- this.retentionPolicyIsLocked = firstNonNull(retentionPolicyIsLocked, Data.nullOf(Boolean.class));
+ this.retentionPolicyIsLocked =
+ firstNonNull(retentionPolicyIsLocked, Data.nullOf(Boolean.class));
return this;
}
@@ -683,45 +673,66 @@ public BucketInfo build() {
retentionPeriod = builder.retentionPeriod;
}
- /**
- * Returns the service-generated id for the bucket.
- */
+ /** Returns the service-generated id for the bucket. */
public String getGeneratedId() {
return generatedId;
}
- /**
- * Returns the bucket's name.
- */
+ /** Returns the bucket's name. */
public String getName() {
return name;
}
- /**
- * Returns the bucket's owner. This is always the project team's owner group.
- */
+ /** Returns the bucket's owner. This is always the project team's owner group. */
public Entity getOwner() {
return owner;
}
- /**
- * Returns the URI of this bucket as a string.
- */
+ /** Returns the URI of this bucket as a string. */
public String getSelfLink() {
return selfLink;
}
/**
- * Returns {@code true} if versioning is fully enabled for this bucket, {@code false} otherwise.
+ * Returns a {@code Boolean} with either {@code true}, {@code null} and in certain cases {@code
+ * false}.
+ *
+ * Case 1: {@code true} the field {@link
+ * com.google.cloud.storage.Storage.BucketField#VERSIONING} is selected in a {@link
+ * Storage#get(String, Storage.BucketGetOption...)} and versions for the bucket is enabled.
+ *
+ *
Case 2.1: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BucketField#VERSIONING} is selected in a {@link
+ * Storage#get(String, Storage.BucketGetOption...)}, but versions for the bucket is not enabled.
+ * This case can be considered implicitly {@code false}.
+ *
+ *
Case 2.2: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BucketField#VERSIONING} is not selected in a {@link
+ * Storage#get(String, Storage.BucketGetOption...)}, and the state for this field is unknown.
+ *
+ *
Case 3: {@code false} versions is explicitly set to false client side for a follow-up
+ * request for example {@link Storage#update(BucketInfo, Storage.BucketTargetOption...)} in which
+ * case the value of versions will remain {@code false} for for the given instance.
*/
public Boolean versioningEnabled() {
return Data.isNull(versioningEnabled) ? null : versioningEnabled;
}
/**
- * Returns {@code true} if a user accessing the bucket or an object it contains should assume the transit costs
- * related to the access, {@code false} otherwise.
+ * Returns a {@code Boolean} with either {@code true}, {@code false}, and in a specific case
+ * {@code null}.
+ *
+ *
Case 1: {@code true} the field {@link com.google.cloud.storage.Storage.BucketField#BILLING}
+ * is selected in a {@link Storage#get(String, Storage.BucketGetOption...)} and requester pays for
+ * the bucket is enabled.
+ *
+ *
Case 2: {@code false} the field {@link com.google.cloud.storage.Storage.BucketField#BILLING}
+ * in a {@link Storage#get(String, Storage.BucketGetOption...)} is selected and requester pays for
+ * the bucket is disable.
*
+ *
Case 3: {@code null} the field {@link com.google.cloud.storage.Storage.BucketField#BILLING}
+ * in a {@link Storage#get(String, Storage.BucketGetOption...)} is not selected, the value is
+ * unknown.
*/
public Boolean requesterPays() {
return Data.isNull(requesterPays) ? null : requesterPays;
@@ -735,9 +746,7 @@ public String getIndexPage() {
return indexPage;
}
- /**
- * Returns the custom object to return when a requested resource is not found.
- */
+ /** Returns the custom object to return when a requested resource is not found. */
public String getNotFoundPage() {
return notFoundPage;
}
@@ -760,16 +769,12 @@ public String getEtag() {
return etag;
}
- /**
- * Returns the time at which the bucket was created.
- */
+ /** Returns the time at which the bucket was created. */
public Long getCreateTime() {
return createTime;
}
- /**
- * Returns the metadata generation of this bucket.
- */
+ /** Returns the metadata generation of this bucket. */
public Long getMetageneration() {
return metageneration;
}
@@ -797,8 +802,8 @@ public StorageClass getStorageClass() {
/**
* Returns the bucket's Cross-Origin Resource Sharing (CORS) configuration.
*
- * @see
- * Cross-Origin Resource Sharing (CORS)
+ * @see Cross-Origin Resource Sharing
+ * (CORS)
*/
public List getCors() {
return cors;
@@ -824,45 +829,78 @@ public List getDefaultAcl() {
return defaultAcl;
}
- /**
- * Returns the labels for this bucket.
- */
+ /** Returns the labels for this bucket. */
public Map getLabels() {
return labels;
}
- /**
- * Returns the default Cloud KMS key to be applied to newly inserted objects in this bucket.
- */
+ /** Returns the default Cloud KMS key to be applied to newly inserted objects in this bucket. */
public String getDefaultKmsKeyName() {
return defaultKmsKeyName;
}
/**
- * Returns the default event based hold value used for inserted objects in this bucket.
+ * Returns a {@code Boolean} with either {@code true}, {@code null} and in certain cases {@code
+ * false}.
+ *
+ * Case 1: {@code true} the field {@link
+ * com.google.cloud.storage.Storage.BucketField#DEFAULT_EVENT_BASED_HOLD} is selected in a {@link
+ * Storage#get(String, Storage.BucketGetOption...)} and default event-based hold for the bucket is
+ * enabled.
+ *
+ *
Case 2.1: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BucketField#DEFAULT_EVENT_BASED_HOLD} is selected in a {@link
+ * Storage#get(String, Storage.BucketGetOption...)}, but default event-based hold for the bucket
+ * is not enabled. This case can be considered implicitly {@code false}.
+ *
+ *
Case 2.2: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BucketField#DEFAULT_EVENT_BASED_HOLD} is not selected in a
+ * {@link Storage#get(String, Storage.BucketGetOption...)}, and the state for this field is
+ * unknown.
+ *
+ *
Case 3: {@code false} default event-based hold is explicitly set to false using in a {@link
+ * Builder#setDefaultEventBasedHold(Boolean)} client side for a follow-up request e.g. {@link
+ * Storage#update(BucketInfo, Storage.BucketTargetOption...)} in which case the value of default
+ * event-based hold will remain {@code false} for the given instance.
*/
- public Boolean getDefaultEventBasedHold() { return defaultEventBasedHold; }
+ public Boolean getDefaultEventBasedHold() {
+ return Data.isNull(defaultEventBasedHold) ? null : defaultEventBasedHold;
+ }
/**
- * Returns the retention effective time a policy took effect if a retention policy is defined.
+ * Returns the retention effective time a policy took effect if a retention policy is defined as a
+ * {@code Long}.
*/
- public Long getRetentionEffectiveTime() { return retentionEffectiveTime; }
+ public Long getRetentionEffectiveTime() {
+ return retentionEffectiveTime;
+ }
/**
- * Returns {@code true} if the bucket retention policy is locked, {@code false} otherwise.
+ * Returns a {@code Boolean} with either {@code true} or {@code null}.
+ *
+ *
Case 1: {@code true} the field {@link
+ * com.google.cloud.storage.Storage.BucketField#RETENTION_POLICY} is selected in a {@link
+ * Storage#get(String, Storage.BucketGetOption...)} and retention policy for the bucket is locked.
+ *
+ *
Case 2.1: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BucketField#RETENTION_POLICY} is selected in a {@link
+ * Storage#get(String, Storage.BucketGetOption...)}, but retention policy for the bucket is not
+ * locked. This case can be considered implicitly {@code false}.
+ *
+ *
Case 2.2: {@code null} the field {@link
+ * com.google.cloud.storage.Storage.BucketField#RETENTION_POLICY} is not selected in a {@link
+ * Storage#get(String, Storage.BucketGetOption...)}, and the state for this field is unknown.
*/
public Boolean retentionPolicyIsLocked() {
return Data.isNull(retentionPolicyIsLocked) ? null : retentionPolicyIsLocked;
}
- /**
- * Returns the retention policy retention period.
- */
- public Long getRetentionPeriod() { return retentionPeriod; }
+ /** Returns the retention policy retention period. */
+ public Long getRetentionPeriod() {
+ return retentionPeriod;
+ }
- /**
- * Returns a builder for the current bucket.
- */
+ /** Returns a builder for the current bucket. */
public Builder toBuilder() {
return new BuilderImpl(this);
}
@@ -876,15 +914,13 @@ public int hashCode() {
public boolean equals(Object obj) {
return obj == this
|| obj != null
- && obj.getClass().equals(BucketInfo.class)
- && Objects.equals(toPb(), ((BucketInfo) obj).toPb());
+ && obj.getClass().equals(BucketInfo.class)
+ && Objects.equals(toPb(), ((BucketInfo) obj).toPb());
}
@Override
public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("name", name)
- .toString();
+ return MoreObjects.toStringHelper(this).add("name", name).toString();
}
com.google.api.services.storage.model.Bucket toPb() {
@@ -909,20 +945,26 @@ com.google.api.services.storage.model.Bucket toPb() {
bucketPb.setCors(transform(cors, Cors.TO_PB_FUNCTION));
}
if (acl != null) {
- bucketPb.setAcl(transform(acl, new Function() {
- @Override
- public BucketAccessControl apply(Acl acl) {
- return acl.toBucketPb();
- }
- }));
+ bucketPb.setAcl(
+ transform(
+ acl,
+ new Function() {
+ @Override
+ public BucketAccessControl apply(Acl acl) {
+ return acl.toBucketPb();
+ }
+ }));
}
if (defaultAcl != null) {
- bucketPb.setDefaultObjectAcl(transform(defaultAcl, new Function() {
- @Override
- public ObjectAccessControl apply(Acl acl) {
- return acl.toObjectPb();
- }
- }));
+ bucketPb.setDefaultObjectAcl(
+ transform(
+ defaultAcl,
+ new Function() {
+ @Override
+ public ObjectAccessControl apply(Acl acl) {
+ return acl.toObjectPb();
+ }
+ }));
}
if (owner != null) {
bucketPb.setOwner(new Owner().setEntity(owner.toPb()));
@@ -944,12 +986,15 @@ public ObjectAccessControl apply(Acl acl) {
}
if (deleteRules != null) {
Lifecycle lifecycle = new Lifecycle();
- lifecycle.setRule(transform(deleteRules, new Function() {
- @Override
- public Rule apply(DeleteRule deleteRule) {
- return deleteRule.toPb();
- }
- }));
+ lifecycle.setRule(
+ transform(
+ deleteRules,
+ new Function() {
+ @Override
+ public Rule apply(DeleteRule deleteRule) {
+ return deleteRule.toPb();
+ }
+ }));
bucketPb.setLifecycle(lifecycle);
}
if (labels != null) {
@@ -961,33 +1006,33 @@ public Rule apply(DeleteRule deleteRule) {
if (defaultEventBasedHold != null) {
bucketPb.setDefaultEventBasedHold(defaultEventBasedHold);
}
- if (retentionPeriod != null || retentionEffectiveTime != null || retentionPolicyIsLocked != null) {
- Bucket.RetentionPolicy retentionPolicy = new Bucket.RetentionPolicy();
- if (retentionPeriod != null) {
+ if (retentionPeriod != null) {
+ if (Data.isNull(retentionPeriod)) {
+ bucketPb.setRetentionPolicy(
+ Data.nullOf(Bucket.RetentionPolicy.class));
+ } else {
+ Bucket.RetentionPolicy retentionPolicy = new Bucket.RetentionPolicy();
retentionPolicy.setRetentionPeriod(retentionPeriod);
+ if (retentionEffectiveTime != null) {
+ retentionPolicy.setEffectiveTime(new DateTime(retentionEffectiveTime));
+ }
+ if (retentionPolicyIsLocked != null) {
+ retentionPolicy.setIsLocked(retentionPolicyIsLocked);
+ }
+ bucketPb.setRetentionPolicy(retentionPolicy);
+
}
- if (retentionEffectiveTime != null) {
- retentionPolicy.setEffectiveTime(new DateTime(retentionEffectiveTime));
- }
- if (retentionPolicyIsLocked != null) {
- retentionPolicy.setIsLocked(retentionPolicyIsLocked);
- }
- bucketPb.setRetentionPolicy(retentionPolicy);
}
return bucketPb;
}
- /**
- * Creates a {@code BucketInfo} object for the provided bucket name.
- */
+ /** Creates a {@code BucketInfo} object for the provided bucket name. */
public static BucketInfo of(String name) {
return newBuilder(name).build();
}
- /**
- * Returns a {@code BucketInfo} builder where the bucket's name is set to the provided name.
- */
+ /** Returns a {@code BucketInfo} builder where the bucket's name is set to the provided name. */
public static Builder newBuilder(String name) {
return new BuilderImpl(name);
}
@@ -1019,21 +1064,26 @@ static BucketInfo fromPb(com.google.api.services.storage.model.Bucket bucketPb)
builder.setCors(transform(bucketPb.getCors(), Cors.FROM_PB_FUNCTION));
}
if (bucketPb.getAcl() != null) {
- builder.setAcl(transform(bucketPb.getAcl(), new Function() {
- @Override
- public Acl apply(BucketAccessControl bucketAccessControl) {
- return Acl.fromPb(bucketAccessControl);
- }
- }));
+ builder.setAcl(
+ transform(
+ bucketPb.getAcl(),
+ new Function() {
+ @Override
+ public Acl apply(BucketAccessControl bucketAccessControl) {
+ return Acl.fromPb(bucketAccessControl);
+ }
+ }));
}
if (bucketPb.getDefaultObjectAcl() != null) {
- builder.setDefaultAcl(transform(bucketPb.getDefaultObjectAcl(),
- new Function() {
- @Override
- public Acl apply(ObjectAccessControl objectAccessControl) {
- return Acl.fromPb(objectAccessControl);
- }
- }));
+ builder.setDefaultAcl(
+ transform(
+ bucketPb.getDefaultObjectAcl(),
+ new Function() {
+ @Override
+ public Acl apply(ObjectAccessControl objectAccessControl) {
+ return Acl.fromPb(objectAccessControl);
+ }
+ }));
}
if (bucketPb.getOwner() != null) {
builder.setOwner(Entity.fromPb(bucketPb.getOwner().getEntity()));
@@ -1047,13 +1097,15 @@ public Acl apply(ObjectAccessControl objectAccessControl) {
builder.setNotFoundPage(website.getNotFoundPage());
}
if (bucketPb.getLifecycle() != null && bucketPb.getLifecycle().getRule() != null) {
- builder.setDeleteRules(transform(bucketPb.getLifecycle().getRule(),
- new Function() {
- @Override
- public DeleteRule apply(Rule rule) {
- return DeleteRule.fromPb(rule);
- }
- }));
+ builder.setDeleteRules(
+ transform(
+ bucketPb.getLifecycle().getRule(),
+ new Function() {
+ @Override
+ public DeleteRule apply(Rule rule) {
+ return DeleteRule.fromPb(rule);
+ }
+ }));
}
if (bucketPb.getLabels() != null) {
builder.setLabels(bucketPb.getLabels());
@@ -1063,7 +1115,9 @@ public DeleteRule apply(Rule rule) {
builder.setRequesterPays(billing.getRequesterPays());
}
Encryption encryption = bucketPb.getEncryption();
- if (encryption != null && encryption.getDefaultKmsKeyName() != null && !encryption.getDefaultKmsKeyName().isEmpty()) {
+ if (encryption != null
+ && encryption.getDefaultKmsKeyName() != null
+ && !encryption.getDefaultKmsKeyName().isEmpty()) {
builder.setDefaultKmsKeyName(encryption.getDefaultKmsKeyName());
}
if (bucketPb.getDefaultEventBasedHold() != null) {
diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
index b67fe2645541..c00ef60e94aa 100644
--- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
+++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
@@ -137,6 +137,7 @@ enum BlobField implements FieldSelector {
SIZE("size"),
STORAGE_CLASS("storageClass"),
TIME_DELETED("timeDeleted"),
+ TIME_CREATED("timeCreated"),
KMS_KEY_NAME("kmsKeyName"),
EVENT_BASED_HOLD("eventBasedHold"),
TEMPORARY_HOLD("temporaryHold"),
diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/testing/RemoteStorageHelper.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/testing/RemoteStorageHelper.java
index f637f5cee4cf..666b9ed6449b 100644
--- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/testing/RemoteStorageHelper.java
+++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/testing/RemoteStorageHelper.java
@@ -20,6 +20,7 @@
import com.google.api.gax.retrying.RetrySettings;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.http.HttpTransportOptions;
+import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Bucket;
@@ -80,6 +81,12 @@ public void run() {
for (Bucket bucket : buckets.iterateAll()) {
if (bucket.getCreateTime() < olderThan) {
try {
+ for (Blob blob : bucket.list(BlobListOption.fields(Storage.BlobField.EVENT_BASED_HOLD,
+ Storage.BlobField.TEMPORARY_HOLD)).iterateAll()) {
+ if(blob.getEventBasedHold() == true || blob.getTemporaryHold() == true) {
+ storage.update(blob.toBuilder().setTemporaryHold(false).setEventBasedHold(false).build());
+ }
+ }
forceDelete(storage, bucket.getName());
} catch (Exception e) {
// Ignore the exception, maybe the bucket is being deleted by someone else.
diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
index a771abe4704e..5b407b30bf32 100644
--- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
+++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
@@ -2058,6 +2058,8 @@ public void testRetentionPolicyNoLock() throws ExecutionException, InterruptedEx
assertNotNull(remoteBlob.getRetentionExpirationTime());
remoteBucket = remoteBucket.toBuilder().setRetentionPeriod(null).build().update();
assertNull(remoteBucket.getRetentionPeriod());
+ remoteBucket = remoteBucket.toBuilder().setRetentionPeriod(null).build().update();
+ assertNull(remoteBucket.getRetentionPeriod());
} finally {
RemoteStorageHelper.forceDelete(storage, bucketName, 5, TimeUnit.SECONDS);
}
@@ -2081,7 +2083,7 @@ private void retentionPolicyLockRequesterPays(boolean requesterPays) throws Exec
}
Bucket remoteBucket = storage.create(bucketInfo);
try {
- assertFalse(remoteBucket.retentionPolicyIsLocked());
+ assertNull(remoteBucket.retentionPolicyIsLocked());
assertNotNull(remoteBucket.getRetentionEffectiveTime());
assertNotNull(remoteBucket.getMetageneration());
if (requesterPays) {
@@ -2186,7 +2188,7 @@ public void testAttemptDeletionObjectTemporaryHold() {
}
@Test
- public void testGetServiceAccount() throws InterruptedException {
+ public void testGetServiceAccount() {
String projectId = remoteStorageHelper.getOptions().getProjectId();
ServiceAccount serviceAccount = storage.getServiceAccount(projectId);
assertNotNull(serviceAccount);
diff --git a/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java b/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java
index 9d943c87331e..0a9a14599cf2 100644
--- a/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java
+++ b/google-cloud-examples/src/main/java/com/google/cloud/examples/storage/snippets/StorageSnippets.java
@@ -57,6 +57,7 @@
import com.google.cloud.storage.StorageClass;
import com.google.cloud.storage.StorageException;
import com.google.cloud.storage.StorageOptions;
+import java.util.Date;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
@@ -1113,4 +1114,280 @@ public Bucket setDefaultKmsKey(String bucketName, String kmsKeyName) throws Stor
// [END storage_set_bucket_default_kms_key]
return bucket;
}
+
+ /** Example of displaying Blob metadata */
+ public void getBlobMetadata(String bucketName, String blobName) throws StorageException {
+ // [START storage_get_metadata]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ // The name of a blob, e.g. "my-blob"
+ // String blobName = "my-blob";
+
+ // Select all fields
+ // Fields can be selected individually e.g. Storage.BlobField.CACHE_CONTROL
+ Blob blob = storage.get(bucketName, blobName, BlobGetOption.fields(Storage.BlobField.values()));
+
+ // Print blob metadata
+ System.out.println("Bucket: " + blob.getBucket());
+ System.out.println("CacheControl: " + blob.getCacheControl());
+ System.out.println("ComponentCount: " + blob.getComponentCount());
+ System.out.println("ContentDisposition: " + blob.getContentDisposition());
+ System.out.println("ContentEncoding: " + blob.getContentEncoding());
+ System.out.println("ContentLanguage: " + blob.getContentLanguage());
+ System.out.println("ContentType: " + blob.getContentType());
+ System.out.println("Crc32c: " + blob.getCrc32c());
+ System.out.println("ETag: " + blob.getEtag());
+ System.out.println("Generation: " + blob.getGeneration());
+ System.out.println("Id: " + blob.getBlobId());
+ System.out.println("KmsKeyName: " + blob.getKmsKeyName());
+ System.out.println("Md5Hash: " + blob.getMd5());
+ System.out.println("MediaLink: " + blob.getMediaLink());
+ System.out.println("Metageneration: " + blob.getMetageneration());
+ System.out.println("Name: " + blob.getName());
+ System.out.println("Size: " + blob.getSize());
+ System.out.println("StorageClass: " + blob.getStorageClass());
+ System.out.println("TimeCreated: " + new Date(blob.getCreateTime()));
+ System.out.println("Last Metadata Update: " + new Date(blob.getUpdateTime()));
+ Boolean temporaryHoldIsEnabled = (blob.getTemporaryHold() != null && blob.getTemporaryHold());
+ System.out.println("temporaryHold: " + (temporaryHoldIsEnabled ? "enabled" : "disabled"));
+ Boolean eventBasedHoldIsEnabled = (blob.getEventBasedHold() != null && blob.getEventBasedHold());
+ System.out.println("eventBasedHold: " + (eventBasedHoldIsEnabled ? "enabled" : "disabled"));
+ if (blob.getRetentionExpirationTime() != null) {
+ System.out.println("retentionExpirationTime: " + new Date(blob.getRetentionExpirationTime()));
+ }
+ if (blob.getMetadata() != null) {
+ System.out.println("\n\n\nUser metadata:");
+ for (Map.Entry userMetadata : blob.getMetadata().entrySet()) {
+ System.out.println(userMetadata.getKey() + "=" + userMetadata.getValue());
+ }
+ }
+ // [END storage_get_metadata]
+ }
+
+ /** Example of setting a retention policy on a bucket */
+ public Bucket setRetentionPolicy(String bucketName, Long retentionPeriod)
+ throws StorageException {
+ // [START storage_set_retention_policy]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ // The retention period for objects in bucket
+ // Long retentionPeriod = 3600L; // 1 hour in seconds
+
+ Bucket bucketWithRetentionPolicy =
+ storage.update(
+ BucketInfo.newBuilder(bucketName).setRetentionPeriod(retentionPeriod).build());
+
+ System.out.println(
+ "Retention period for " + bucketName + " is now " + bucketWithRetentionPolicy.getRetentionPeriod());
+ // [END storage_set_retention_policy]
+ return bucketWithRetentionPolicy;
+ }
+
+ /** Example of removing a retention policy on a bucket */
+ public Bucket removeRetentionPolicy(String bucketName) throws StorageException, IllegalArgumentException {
+ // [START storage_remove_retention_policy]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ Bucket bucket = storage.get(bucketName, BucketGetOption.fields(BucketField.RETENTION_POLICY));
+ if (bucket.retentionPolicyIsLocked() != null && bucket.retentionPolicyIsLocked()) {
+ throw new IllegalArgumentException("Unable to remove retention period as retention policy is locked.");
+ }
+
+ Bucket bucketWithoutRetentionPolicy = bucket.toBuilder().setRetentionPeriod(null).build().update();
+
+ System.out.println("Retention period for " + bucketName + " has been removed");
+ // [END storage_remove_retention_policy]
+ return bucketWithoutRetentionPolicy;
+ }
+
+ /** Example of removing a retention policy on a bucket */
+ public Bucket getRetentionPolicy(String bucketName) throws StorageException {
+ // [START storage_get_retention_policy]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ Bucket bucket = storage.get(bucketName, BucketGetOption.fields(BucketField.RETENTION_POLICY));
+
+ System.out.println("Retention Policy for " + bucketName);
+ System.out.println("Retention Period: " + bucket.getRetentionPeriod());
+ if (bucket.retentionPolicyIsLocked() != null && bucket.retentionPolicyIsLocked()) {
+ System.out.println("Retention Policy is locked");
+ }
+ if (bucket.getRetentionEffectiveTime() != null) {
+ System.out.println("Effective Time: " + new Date(bucket.getRetentionEffectiveTime()));
+ }
+ // [END storage_get_retention_policy]
+ return bucket;
+ }
+
+ /** Example of how to lock a bucket retention policy */
+ public Bucket lockRetentionPolicy(String bucketName) throws StorageException {
+ // [START storage_lock_retention_policy]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ Bucket bucket =
+ storage.get(bucketName, Storage.BucketGetOption.fields(BucketField.METAGENERATION));
+ Bucket lockedBucket =
+ bucket.lockRetentionPolicy(Storage.BucketTargetOption.metagenerationMatch());
+
+ System.out.println("Retention period for " + bucketName + " is now locked");
+ System.out.println(
+ "Retention policy effective as of " + new Date(lockedBucket.getRetentionEffectiveTime()));
+ // [END storage_lock_retention_policy]
+ return lockedBucket;
+ }
+
+ /** Example of how to enable default event-based hold for a bucket */
+ public Bucket enableDefaultEventBasedHold(String bucketName) throws StorageException {
+ // [START storage_enable_default_event_based_hold]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ Bucket bucket =
+ storage.update(BucketInfo.newBuilder(bucketName).setDefaultEventBasedHold(true).build());
+
+ System.out.println("Default event-based hold was enabled for " + bucketName);
+ // [END storage_enable_default_event_based_hold]
+ return bucket;
+ }
+
+ /** Example of how to disable default event-based hold for a bucket */
+ public Bucket disableDefaultEventBasedHold(String bucketName) throws StorageException {
+ // [START storage_disable_default_event_based_hold]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ Bucket bucket =
+ storage.update(BucketInfo.newBuilder(bucketName).setDefaultEventBasedHold(false).build());
+
+ System.out.println("Default event-based hold was disabled for " + bucketName);
+ // [END storage_disable_default_event_based_hold]
+ return bucket;
+ }
+
+ /** Example of how to get default event-based hold for a bucket */
+ public Bucket getDefaultEventBasedHold(String bucketName) throws StorageException {
+ // [START storage_get_default_event_based_hold]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ Bucket bucket =
+ storage.get(bucketName, BucketGetOption.fields(BucketField.DEFAULT_EVENT_BASED_HOLD));
+
+ if (bucket.getDefaultEventBasedHold() != null && bucket.getDefaultEventBasedHold()) {
+ System.out.println("Default event-based hold is enabled for " + bucketName);
+ } else {
+ System.out.println("Default event-based hold is not enabled for " + bucketName);
+ }
+ // [END storage_get_default_event_based_hold]
+ return bucket;
+ }
+
+ /** Example of how to set event-based hold for a blob */
+ public Blob setEventBasedHold(String bucketName, String blobName) throws StorageException {
+ // [START storage_set_event_based_hold]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ // The name of a blob, e.g. "my-blob"
+ // String blobName = "my-blob";
+
+ BlobId blobId = BlobId.of(bucketName, blobName);
+ Blob blob = storage.update(BlobInfo.newBuilder(blobId).setEventBasedHold(true).build());
+
+ System.out.println("Event-based hold was set for " + blobName);
+ // [END storage_set_event_based_hold]
+ return blob;
+ }
+
+ /** Example of how to release event-based hold for a blob */
+ public Blob releaseEventBasedHold(String bucketName, String blobName) throws StorageException {
+ // [START storage_release_event_based_hold]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ // The name of a blob, e.g. "my-blob"
+ // String blobName = "my-blob";
+
+ BlobId blobId = BlobId.of(bucketName, blobName);
+ Blob blob = storage.update(BlobInfo.newBuilder(blobId).setEventBasedHold(false).build());
+
+ System.out.println("Event-based hold was released for " + blobName);
+ // [END storage_release_event_based_hold]
+ return blob;
+ }
+
+ /** Example of how to set a temporary hold for a blob */
+ public Blob setTemporaryHold(String bucketName, String blobName) throws StorageException {
+ // [START storage_set_temporary_hold]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ // The name of a blob, e.g. "my-blob"
+ // String blobName = "my-blob";
+
+ BlobId blobId = BlobId.of(bucketName, blobName);
+ Blob blob = storage.update(BlobInfo.newBuilder(blobId).setTemporaryHold(true).build());
+
+ System.out.println("Temporary hold was set for " + blobName);
+ // [END storage_set_temporary_hold]
+ return blob;
+ }
+
+ /** Example of how to release a temporary hold for a blob */
+ public Blob releaseTemporaryHold(String bucketName, String blobName) throws StorageException {
+ // [START storage_release_temporary_hold]
+ // Instantiate a Google Cloud Storage client
+ Storage storage = StorageOptions.getDefaultInstance().getService();
+
+ // The name of a bucket, e.g. "my-bucket"
+ // String bucketName = "my-bucket";
+
+ // The name of a blob, e.g. "my-blob"
+ // String blobName = "my-blob";
+
+ BlobId blobId = BlobId.of(bucketName, blobName);
+ Blob blob = storage.update(BlobInfo.newBuilder(blobId).setTemporaryHold(false).build());
+
+ System.out.println("Temporary hold was released for " + blobName);
+ // [END storage_release_temporary_hold]
+ return blob;
+ }
}
diff --git a/google-cloud-examples/src/test/java/com/google/cloud/examples/storage/snippets/ITStorageSnippets.java b/google-cloud-examples/src/test/java/com/google/cloud/examples/storage/snippets/ITStorageSnippets.java
index fffd0c3eb5b5..edfbdad30514 100644
--- a/google-cloud-examples/src/test/java/com/google/cloud/examples/storage/snippets/ITStorageSnippets.java
+++ b/google-cloud-examples/src/test/java/com/google/cloud/examples/storage/snippets/ITStorageSnippets.java
@@ -38,6 +38,7 @@
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageException;
import com.google.cloud.storage.testing.RemoteStorageHelper;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
@@ -48,13 +49,15 @@
import org.junit.rules.ExpectedException;
import org.junit.rules.Timeout;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.PrintStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Paths;
-import java.util.ArrayList;
+import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -74,7 +77,7 @@ public class ITStorageSnippets {
private static final String KMS_KEY_NAME =
"projects/gcloud-devel/locations/us/" + "keyRings/gcs_kms_key_ring_us/cryptoKeys/key";
-
+ private static final Long RETENTION_PERIOD = 5L; // 5 seconds
private static Storage storage;
private static StorageSnippets storageSnippets;
private static List bucketsToCleanUp;
@@ -87,20 +90,22 @@ public class ITStorageSnippets {
public static void beforeClass() {
RemoteStorageHelper helper = RemoteStorageHelper.create();
storage = helper.getOptions().getService();
- bucketsToCleanUp = new ArrayList();
storageSnippets = new StorageSnippets(storage);
storageSnippets.createBucket(BUCKET);
- bucketsToCleanUp.add(BUCKET);
}
@AfterClass
public static void afterClass() throws ExecutionException, InterruptedException {
if (storage != null) {
- for (String bucket : bucketsToCleanUp) {
- boolean wasDeleted = RemoteStorageHelper.forceDelete(storage, bucket, 5, TimeUnit.SECONDS);
- if (!wasDeleted && log.isLoggable(Level.WARNING)) {
- log.log(Level.WARNING, "Deletion of bucket {0} timed out, bucket is not empty", bucket);
- }
+ // In beforeClass, we make buckets auto-delete blobs older than a day old.
+ // Here, delete all buckets older than 2 days. They should already be empty and easy.
+ long cleanTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2);
+ long cleanTimeout = System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(1);
+ RemoteStorageHelper.cleanBuckets(storage, cleanTime, cleanTimeout);
+
+ boolean wasDeleted = RemoteStorageHelper.forceDelete(storage, BUCKET, 1, TimeUnit.MINUTES);
+ if (!wasDeleted && log.isLoggable(Level.WARNING)) {
+ log.log(Level.WARNING, "Deletion of bucket {0} timed out, bucket is not empty", BUCKET);
}
}
}
@@ -109,7 +114,6 @@ public static void afterClass() throws ExecutionException, InterruptedException
public void testCreateBucketWithStorageClassAndLocation()
throws ExecutionException, InterruptedException {
String tempBucket = RemoteStorageHelper.generateBucketName();
- bucketsToCleanUp.add(tempBucket);
Bucket bucket = storageSnippets.createBucketWithStorageClassAndLocation(tempBucket);
@@ -435,6 +439,45 @@ public void testBlobDownload() throws Exception {
assertArrayEquals(BLOB_BYTE_CONTENT, readBytes);
}
+ @Test
+ public void testGetBlobMetadata() {
+ String blobName = "test-create-empty-blob";
+ BlobId blobId = BlobId.of(BUCKET, blobName);
+ BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setMetadata(ImmutableMap.of("k", "v")).build();
+ Blob remoteBlob = storage.create(blobInfo, BLOB_BYTE_CONTENT);
+ assertNotNull(remoteBlob);
+ final ByteArrayOutputStream snippetOutputCapture = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(snippetOutputCapture));
+ storageSnippets.getBlobMetadata(BUCKET, blobName);
+ String snippetOutput = snippetOutputCapture.toString();
+ System.setOut(System.out);
+ assertTrue(snippetOutput.contains("Bucket: " + remoteBlob.getBucket()));
+ assertTrue(snippetOutput.contains("Bucket: " + remoteBlob.getBucket()));
+ assertTrue(snippetOutput.contains("CacheControl: " + remoteBlob.getCacheControl()));
+ assertTrue(snippetOutput.contains("ComponentCount: " + remoteBlob.getComponentCount()));
+ assertTrue(snippetOutput.contains("ContentDisposition: " + remoteBlob.getContentDisposition()));
+ assertTrue(snippetOutput.contains("ContentEncoding: " + remoteBlob.getContentEncoding()));
+ assertTrue(snippetOutput.contains("ContentLanguage: " + remoteBlob.getContentLanguage()));
+ assertTrue(snippetOutput.contains("ContentType: " + remoteBlob.getContentType()));
+ assertTrue(snippetOutput.contains("Crc32c: " + remoteBlob.getCrc32c()));
+ assertTrue(snippetOutput.contains("ETag: " + remoteBlob.getEtag()));
+ assertTrue(snippetOutput.contains("Generation: " + remoteBlob.getGeneration()));
+ assertTrue(snippetOutput.contains("Id: " + remoteBlob.getBlobId()));
+ assertTrue(snippetOutput.contains("KmsKeyName: " + remoteBlob.getKmsKeyName()));
+ assertTrue(snippetOutput.contains("Md5Hash: " + remoteBlob.getMd5()));
+ assertTrue(snippetOutput.contains("MediaLink: " + remoteBlob.getMediaLink()));
+ assertTrue(snippetOutput.contains("Metageneration: " + remoteBlob.getMetageneration()));
+ assertTrue(snippetOutput.contains("Name: " + remoteBlob.getName()));
+ assertTrue(snippetOutput.contains("Size: " + remoteBlob.getSize()));
+ assertTrue(snippetOutput.contains("StorageClass: " + remoteBlob.getStorageClass()));
+ assertTrue(snippetOutput.contains("TimeCreated: " + new Date(remoteBlob.getCreateTime())));
+ assertTrue(snippetOutput.contains("Last Metadata Update: " + new Date(remoteBlob.getUpdateTime())));
+ assertTrue(snippetOutput.contains("temporaryHold: disabled"));
+ assertTrue(snippetOutput.contains("eventBasedHold: disabled"));
+ assertTrue(snippetOutput.contains("User metadata:"));
+ assertTrue(snippetOutput.contains("k=v"));
+ }
+
@Test
public void testRequesterPays() throws Exception {
Bucket bucket = storageSnippets.enableRequesterPays(BUCKET);
@@ -461,4 +504,47 @@ public void testDefaultKMSKey() {
// Remove default key
storageSnippets.setDefaultKmsKey(BUCKET, null);
}
+
+ @Test
+ public void testBucketRetention() {
+ Bucket bucket = storageSnippets.setRetentionPolicy(BUCKET, RETENTION_PERIOD);
+ assertEquals(bucket.getRetentionPeriod(), RETENTION_PERIOD);
+ assertNotNull(bucket.getRetentionEffectiveTime());
+ bucket = storageSnippets.getRetentionPolicy(BUCKET);
+ assertEquals(bucket.getRetentionPeriod(), RETENTION_PERIOD);
+ assertNotNull(bucket.getRetentionEffectiveTime());
+ assertNull(bucket.retentionPolicyIsLocked());
+ bucket = storageSnippets.enableDefaultEventBasedHold(BUCKET);
+ assertTrue(bucket.getDefaultEventBasedHold());
+ bucket = storageSnippets.getDefaultEventBasedHold(BUCKET);
+ assertTrue(bucket.getDefaultEventBasedHold());
+ String blobName = "test-create-empty-blob-retention-policy";
+ Blob remoteBlob = bucket.create(blobName, BLOB_BYTE_CONTENT);
+ assertTrue(remoteBlob.getEventBasedHold());
+ remoteBlob = storageSnippets.setEventBasedHold(BUCKET, blobName);
+ assertTrue(remoteBlob.getEventBasedHold());
+ remoteBlob = storageSnippets.releaseEventBasedHold(BUCKET, blobName);
+ assertFalse(remoteBlob.getEventBasedHold());
+ assertNotNull(remoteBlob.getRetentionExpirationTime());
+ bucket = storageSnippets.removeRetentionPolicy(BUCKET);
+ assertNull(bucket.getRetentionPeriod());
+ assertNull(bucket.getRetentionEffectiveTime());
+ bucket = storageSnippets.disableDefaultEventBasedHold(BUCKET);
+ assertFalse(bucket.getDefaultEventBasedHold());
+ remoteBlob = storageSnippets.setTemporaryHold(BUCKET, blobName);
+ assertTrue(remoteBlob.getTemporaryHold());
+ remoteBlob = storageSnippets.releaseTemporaryHold(BUCKET, blobName);
+ assertFalse(remoteBlob.getTemporaryHold());
+ }
+
+ @Test
+ public void testLockRetentionPolicy() {
+ String tempBucket = RemoteStorageHelper.generateBucketName();
+ Bucket bucket = storageSnippets.createBucket(tempBucket);
+ assertNotNull(bucket);
+ bucket = storageSnippets.setRetentionPolicy(tempBucket, RETENTION_PERIOD);
+ assertEquals(bucket.getRetentionPeriod(), RETENTION_PERIOD);
+ bucket = storageSnippets.lockRetentionPolicy(tempBucket);
+ assertTrue(bucket.retentionPolicyIsLocked());
+ }
}