diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java index b3e96113b..038df91d9 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java @@ -351,7 +351,9 @@ public LifecycleRule(LifecycleAction action, LifecycleCondition condition) { && condition.getAge() == null && condition.getCreatedBefore() == null && condition.getMatchesStorageClass() == null - && condition.getNumberOfNewerVersions() == null) { + && condition.getNumberOfNewerVersions() == null + && condition.getDaysSinceNoncurrentTime() == null + && condition.getNoncurrentTimeBefore() == null) { throw new IllegalArgumentException( "You must specify at least one condition to use object lifecycle " + "management. Please see https://cloud.google.com/storage/docs/lifecycle for details."); @@ -419,7 +421,13 @@ Rule toPb() { ? null : transform( lifecycleCondition.getMatchesStorageClass(), - Functions.toStringFunction())); + Functions.toStringFunction())) + .setDaysSinceNoncurrentTime(lifecycleCondition.getDaysSinceNoncurrentTime()) + .setNoncurrentTimeBefore( + lifecycleCondition.getNoncurrentTimeBefore() == null + ? null + : new DateTime( + true, lifecycleCondition.getNoncurrentTimeBefore().getValue(), 0)); rule.setCondition(condition); @@ -462,7 +470,9 @@ static LifecycleRule fromPb(Rule rule) { public StorageClass apply(String storageClass) { return StorageClass.valueOf(storageClass); } - })); + })) + .setDaysSinceNoncurrentTime(condition.getDaysSinceNoncurrentTime()) + .setNoncurrentTimeBefore(condition.getNoncurrentTimeBefore()); return new LifecycleRule(lifecycleAction, conditionBuilder.build()); } @@ -480,6 +490,8 @@ public static class LifecycleCondition implements Serializable { private final Integer numberOfNewerVersions; private final Boolean isLive; private final List matchesStorageClass; + private final Integer daysSinceNoncurrentTime; + private final DateTime noncurrentTimeBefore; private LifecycleCondition(Builder builder) { this.age = builder.age; @@ -487,6 +499,8 @@ private LifecycleCondition(Builder builder) { this.numberOfNewerVersions = builder.numberOfNewerVersions; this.isLive = builder.isLive; this.matchesStorageClass = builder.matchesStorageClass; + this.daysSinceNoncurrentTime = builder.daysSinceNoncurrentTime; + this.noncurrentTimeBefore = builder.noncurrentTimeBefore; } public Builder toBuilder() { @@ -495,7 +509,9 @@ public Builder toBuilder() { .setCreatedBefore(this.createdBefore) .setNumberOfNewerVersions(this.numberOfNewerVersions) .setIsLive(this.isLive) - .setMatchesStorageClass(this.matchesStorageClass); + .setMatchesStorageClass(this.matchesStorageClass) + .setDaysSinceNoncurrentTime(this.daysSinceNoncurrentTime) + .setNoncurrentTimeBefore(this.noncurrentTimeBefore); } public static Builder newBuilder() { @@ -510,6 +526,8 @@ public String toString() { .add("numberofNewerVersions", numberOfNewerVersions) .add("isLive", isLive) .add("matchesStorageClass", matchesStorageClass) + .add("daysSinceNoncurrentTime", daysSinceNoncurrentTime) + .add("noncurrentTimeBefore", noncurrentTimeBefore) .toString(); } @@ -533,6 +551,18 @@ public List getMatchesStorageClass() { return matchesStorageClass; } + /** Returns the number of days elapsed since the noncurrent timestamp of an object. */ + public Integer getDaysSinceNoncurrentTime() { + return daysSinceNoncurrentTime; + } + + /** + * Returns the date in RFC 3339 format with only the date part (for instance, "2013-01-15"). + */ + public DateTime getNoncurrentTimeBefore() { + return noncurrentTimeBefore; + } + /** Builder for {@code LifecycleCondition}. */ public static class Builder { private Integer age; @@ -540,6 +570,8 @@ public static class Builder { private Integer numberOfNewerVersions; private Boolean isLive; private List matchesStorageClass; + private Integer daysSinceNoncurrentTime; + private DateTime noncurrentTimeBefore; private Builder() {} @@ -594,6 +626,29 @@ public Builder setMatchesStorageClass(List matchesStorageClass) { return this; } + /** + * Sets the number of days elapsed since the noncurrent timestamp of an object. The + * condition is satisfied if the days elapsed is at least this number. This condition is + * relevant only for versioned objects. The value of the field must be a nonnegative + * integer. If it's zero, the object version will become eligible for Lifecycle action as + * soon as it becomes noncurrent. + */ + public Builder setDaysSinceNoncurrentTime(Integer daysSinceNoncurrentTime) { + this.daysSinceNoncurrentTime = daysSinceNoncurrentTime; + return this; + } + + /** + * Sets the date in RFC 3339 format with only the date part (for instance, "2013-01-15"). + * Note that only date part will be considered, if the time is specified it will be + * truncated. This condition is satisfied when the noncurrent time on an object is before + * this date. This condition is relevant only for versioned objects. + */ + public Builder setNoncurrentTimeBefore(DateTime noncurrentTimeBefore) { + this.noncurrentTimeBefore = noncurrentTimeBefore; + return this; + } + /** Builds a {@code LifecycleCondition} object. * */ public LifecycleCondition build() { return new LifecycleCondition(this); diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java index 425cfb702..c7b3aa198 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import com.google.api.client.util.DateTime; import com.google.api.services.storage.model.Bucket; import com.google.api.services.storage.model.Bucket.Lifecycle.Rule; import com.google.cloud.storage.Acl.Project; @@ -328,6 +329,22 @@ public void testLifecycleRules() { setStorageClassLifecycleRule.getAction().getStorageClass()); assertTrue(setStorageClassLifecycleRule.getCondition().getIsLive()); assertEquals(10, setStorageClassLifecycleRule.getCondition().getNumNewerVersions().intValue()); + + Rule lifecycleRule = + new LifecycleRule( + LifecycleAction.newSetStorageClassAction(StorageClass.COLDLINE), + LifecycleCondition.newBuilder() + .setIsLive(true) + .setNumberOfNewerVersions(10) + .setDaysSinceNoncurrentTime(30) + .setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis())) + .build()) + .toPb(); + assertEquals(StorageClass.COLDLINE.toString(), lifecycleRule.getAction().getStorageClass()); + assertTrue(lifecycleRule.getCondition().getIsLive()); + assertEquals(10, lifecycleRule.getCondition().getNumNewerVersions().intValue()); + assertEquals(30, lifecycleRule.getCondition().getDaysSinceNoncurrentTime().intValue()); + assertNotNull(lifecycleRule.getCondition().getNoncurrentTimeBefore()); } @Test diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java index 24f5ed9e7..35c4e253c 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertTrue; import com.google.api.client.googleapis.json.GoogleJsonError; +import com.google.api.client.util.DateTime; import com.google.api.core.ApiClock; import com.google.api.services.storage.model.Policy.Bindings; import com.google.api.services.storage.model.StorageObject; @@ -2232,4 +2233,40 @@ public void testV4PostPolicy() { assertEquals(outputFields.get("key"), "my-object"); assertEquals("https://storage.googleapis.com/my-bucket/", policy.getUrl()); } + + @Test + public void testBucketLifecycleRules() { + BucketInfo bucketInfo = + BucketInfo.newBuilder("b") + .setLocation("us") + .setLifecycleRules( + ImmutableList.of( + new BucketInfo.LifecycleRule( + BucketInfo.LifecycleRule.LifecycleAction.newSetStorageClassAction( + StorageClass.COLDLINE), + BucketInfo.LifecycleRule.LifecycleCondition.newBuilder() + .setAge(1) + .setNumberOfNewerVersions(3) + .setIsLive(false) + .setCreatedBefore(new DateTime(System.currentTimeMillis())) + .setMatchesStorageClass(ImmutableList.of(StorageClass.COLDLINE)) + .setDaysSinceNoncurrentTime(30) + .setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis())) + .build()))) + .build(); + EasyMock.expect( + storageRpcMock.create(bucketInfo.toPb(), new HashMap())) + .andReturn(bucketInfo.toPb()); + EasyMock.replay(storageRpcMock); + initializeService(); + Bucket bucket = storage.create(bucketInfo); + BucketInfo.LifecycleRule lifecycleRule = bucket.getLifecycleRules().get(0); + assertEquals(3, lifecycleRule.getCondition().getNumberOfNewerVersions().intValue()); + assertNotNull(lifecycleRule.getCondition().getCreatedBefore()); + assertFalse(lifecycleRule.getCondition().getIsLive()); + assertEquals(1, lifecycleRule.getCondition().getAge().intValue()); + assertEquals(1, lifecycleRule.getCondition().getMatchesStorageClass().size()); + assertEquals(30, lifecycleRule.getCondition().getDaysSinceNoncurrentTime().intValue()); + assertNotNull(lifecycleRule.getCondition().getNoncurrentTimeBefore()); + } } diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java index a741f3eb7..d92ca5921 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java @@ -456,6 +456,8 @@ public void testGetBucketLifecycleRules() { .setIsLive(false) .setCreatedBefore(new DateTime(System.currentTimeMillis())) .setMatchesStorageClass(ImmutableList.of(StorageClass.COLDLINE)) + .setDaysSinceNoncurrentTime(30) + .setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis())) .build()))) .build()); Bucket remoteBucket = @@ -472,6 +474,8 @@ public void testGetBucketLifecycleRules() { assertFalse(lifecycleRule.getCondition().getIsLive()); assertEquals(1, lifecycleRule.getCondition().getAge().intValue()); assertEquals(1, lifecycleRule.getCondition().getMatchesStorageClass().size()); + assertEquals(30, lifecycleRule.getCondition().getDaysSinceNoncurrentTime().intValue()); + assertNotNull(lifecycleRule.getCondition().getNoncurrentTimeBefore()); } finally { storage.delete(lifecycleTestBucketName); }