From 8dfc0cbf8294a7fc426948e22e5c2182da97b630 Mon Sep 17 00:00:00 2001
From: Ajit Thakor <49403056+athakor@users.noreply.github.com>
Date: Thu, 25 Jun 2020 20:38:57 +0530
Subject: [PATCH] feat: expose all the methods of notification (#141)
* feat: expose all the methods of notification
* feat: remove unsed code
* feat: fix review changes
* build: fix require upper bound dependencies errors
* build: fix clirr ignore differences
* feat: implement getNotification inside StorageRpcTestBase class and fix the builds checks
---
.../clirr-ignored-differences.xml | 25 ++
google-cloud-storage/pom.xml | 5 +
.../cloud/storage/NotificationInfo.java | 309 ++++++++++++++++++
.../com/google/cloud/storage/Storage.java | 33 ++
.../com/google/cloud/storage/StorageImpl.java | 74 +++++
.../cloud/storage/spi/v1/HttpStorageRpc.java | 15 +
.../storage/spi/v1/HttpStorageRpcSpans.java | 2 +
.../cloud/storage/spi/v1/StorageRpc.java | 8 +
.../storage/testing/StorageRpcTestBase.java | 5 +
.../cloud/storage/NotificationInfoTest.java | 102 ++++++
.../google/cloud/storage/StorageImplTest.java | 90 ++++-
.../cloud/storage/it/ITStorageTest.java | 59 ++++
.../testing/StorageRpcTestBaseTest.java | 11 +
pom.xml | 6 +
14 files changed, 743 insertions(+), 1 deletion(-)
create mode 100644 google-cloud-storage/src/main/java/com/google/cloud/storage/NotificationInfo.java
create mode 100644 google-cloud-storage/src/test/java/com/google/cloud/storage/NotificationInfoTest.java
diff --git a/google-cloud-storage/clirr-ignored-differences.xml b/google-cloud-storage/clirr-ignored-differences.xml
index ace7a6ef0..2aababb9e 100644
--- a/google-cloud-storage/clirr-ignored-differences.xml
+++ b/google-cloud-storage/clirr-ignored-differences.xml
@@ -26,4 +26,29 @@
com.google.cloud.storage.BucketInfo$Builder deleteLifecycleRules()
7013
+
+ com/google/cloud/storage/Storage
+ com.google.api.services.storage.model.Notification createNotification(java.lang.String, com.google.cloud.storage.NotificationInfo)
+ 7012
+
+
+ com/google/cloud/storage/Storage
+ com.google.api.services.storage.model.Notification getNotification(java.lang.String, java.lang.String)
+ 7012
+
+
+ com/google/cloud/storage/Storage
+ java.util.List listNotifications(java.lang.String)
+ 7012
+
+
+ com/google/cloud/storage/Storage
+ boolean deleteNotification(java.lang.String, java.lang.String)
+ 7012
+
+
+ com/google/cloud/storage/spi/v1/StorageRpc
+ com.google.api.services.storage.model.Notification getNotification(java.lang.String, java.lang.String)
+ 7012
+
diff --git a/google-cloud-storage/pom.xml b/google-cloud-storage/pom.xml
index 3e2dbb0ba..1be67d6b3 100644
--- a/google-cloud-storage/pom.xml
+++ b/google-cloud-storage/pom.xml
@@ -155,6 +155,11 @@
truth
test
+
+ com.google.cloud
+ google-cloud-pubsub
+ test
+
org.easymock
easymock
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/NotificationInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/NotificationInfo.java
new file mode 100644
index 000000000..34c2d326d
--- /dev/null
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/NotificationInfo.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.storage;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.pathtemplate.PathTemplate;
+import com.google.api.services.storage.model.Notification;
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Google Storage Notification metadata;
+ *
+ * @see Concepts and
+ * Terminology
+ */
+public class NotificationInfo implements Serializable {
+
+ private static final long serialVersionUID = 5725883368559753810L;
+ private static final PathTemplate PATH_TEMPLATE =
+ PathTemplate.createWithoutUrlEncoding("projects/{project}/topics/{topic}");
+
+ public enum PayloadFormat {
+ JSON_API_V1,
+ NONE
+ }
+
+ static final Function FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public NotificationInfo apply(Notification pb) {
+ return NotificationInfo.fromPb(pb);
+ }
+ };
+ static final Function TO_PB_FUNCTION =
+ new Function() {
+ @Override
+ public Notification apply(NotificationInfo NotificationInfo) {
+ return NotificationInfo.toPb();
+ }
+ };
+ private final String generatedId;
+ private final String topic;
+ private final List eventTypes;
+ private final Map customAttributes;
+ private final PayloadFormat payloadFormat;
+ private final String objectNamePrefix;
+ private final String etag;
+ private final String selfLink;
+
+ public static final class Builder {
+
+ private String generatedId;
+ private String topic;
+ private List eventTypes;
+ private Map customAttributes;
+ private PayloadFormat payloadFormat;
+ private String objectNamePrefix;
+ private String etag;
+ private String selfLink;
+
+ Builder(String topic) {
+ this.topic = topic;
+ }
+
+ Builder(NotificationInfo NotificationInfo) {
+ generatedId = NotificationInfo.generatedId;
+ etag = NotificationInfo.etag;
+ selfLink = NotificationInfo.selfLink;
+ topic = NotificationInfo.topic;
+ eventTypes = NotificationInfo.eventTypes;
+ customAttributes = NotificationInfo.customAttributes;
+ payloadFormat = NotificationInfo.payloadFormat;
+ objectNamePrefix = NotificationInfo.objectNamePrefix;
+ }
+
+ Builder setGeneratedId(String generatedId) {
+ this.generatedId = generatedId;
+ return this;
+ }
+
+ Builder setSelfLink(String selfLink) {
+ this.selfLink = selfLink;
+ return this;
+ }
+
+ /** The name of the topic. It must have the format "projects/{project}/topics/{topic}". */
+ public Builder setTopic(String topic) {
+ this.topic = topic;
+ return this;
+ }
+
+ public Builder setPayloadFormat(PayloadFormat payloadFormat) {
+ this.payloadFormat = payloadFormat;
+ return this;
+ }
+
+ public Builder setObjectNamePrefix(String objectNamePrefix) {
+ this.objectNamePrefix = objectNamePrefix;
+ return this;
+ }
+
+ public Builder setEventTypes(Iterable eventTypes) {
+ this.eventTypes = eventTypes != null ? ImmutableList.copyOf(eventTypes) : null;
+ return this;
+ }
+
+ Builder setEtag(String etag) {
+ this.etag = etag;
+ return this;
+ }
+
+ public Builder setCustomAttributes(Map customAttributes) {
+ this.customAttributes =
+ customAttributes != null ? ImmutableMap.copyOf(customAttributes) : null;
+ return this;
+ }
+
+ public NotificationInfo build() {
+ checkNotNull(topic);
+ return new NotificationInfo(this);
+ }
+ }
+
+ NotificationInfo(Builder builder) {
+ generatedId = builder.generatedId;
+ etag = builder.etag;
+ selfLink = builder.selfLink;
+ topic = builder.topic;
+ eventTypes = builder.eventTypes;
+ customAttributes = builder.customAttributes;
+ payloadFormat = builder.payloadFormat;
+ objectNamePrefix = builder.objectNamePrefix;
+ }
+
+ /** Returns the service-generated id for the notification. */
+ public String getGeneratedId() {
+ return generatedId;
+ }
+
+ /** Returns the topic to which this subscription publishes. */
+ public String getTopic() {
+ return topic;
+ }
+
+ /** Returns the canonical URI of this topic as a string. */
+ public String getSelfLink() {
+ return selfLink;
+ }
+
+ /** Returns the desired content of the Payload. */
+ public PayloadFormat getPayloadFormat() {
+ return payloadFormat;
+ }
+
+ /** Returns the object name prefix for which this notification configuration applies. */
+ public String getObjectNamePrefix() {
+ return objectNamePrefix;
+ }
+
+ /**
+ * Returns HTTP 1.1 Entity tag for the notification.
+ *
+ * @see Entity Tags
+ */
+ public String getEtag() {
+ return etag;
+ }
+
+ /**
+ * Returns the list of event types that this notification will apply to. If empty, notifications
+ * will be sent on all event types.
+ *
+ * @see Cross-Origin Resource Sharing
+ * (CORS)
+ */
+ public List getEventTypes() {
+ return eventTypes;
+ }
+
+ /**
+ * Returns the list of additional attributes to attach to each Cloud PubSub message published for
+ * this notification subscription.
+ *
+ * @see
+ * About Access Control Lists
+ */
+ public Map getCustomAttributes() {
+ return customAttributes;
+ }
+
+ /** Returns a builder for the current notification. */
+ public Builder toBuilder() {
+ return new Builder(this);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getTopic());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this
+ || obj != null
+ && obj.getClass().equals(NotificationInfo.class)
+ && Objects.equals(toPb(), ((NotificationInfo) obj).toPb());
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("topic", getTopic()).toString();
+ }
+
+ Notification toPb() {
+ Notification notificationPb = new Notification();
+ notificationPb.setId(generatedId);
+ notificationPb.setEtag(etag);
+ if (customAttributes != null) {
+ notificationPb.setCustomAttributes(customAttributes);
+ }
+ if (eventTypes != null) {
+ notificationPb.setEventTypes(eventTypes);
+ }
+ if (objectNamePrefix != null) {
+ notificationPb.setObjectNamePrefix(objectNamePrefix);
+ }
+ if (payloadFormat != null) {
+ notificationPb.setPayloadFormat(payloadFormat.toString());
+ } else {
+ notificationPb.setPayloadFormat(PayloadFormat.NONE.toString());
+ }
+ notificationPb.setSelfLink(selfLink);
+ notificationPb.setTopic(topic);
+
+ return notificationPb;
+ }
+
+ /**
+ * Creates a {@code NotificationInfo} object for the provided topic name.
+ *
+ * @param topic The name of the topic. It must have the format
+ * "projects/{project}/topics/{topic}".
+ */
+ public static NotificationInfo of(String topic) {
+ PATH_TEMPLATE.validatedMatch(topic, "topic name must be in valid format");
+ return newBuilder(topic).build();
+ }
+
+ /**
+ * Returns a {@code NotificationInfo} builder where the topic's name is set to the provided name.
+ *
+ * @param topic The name of the topic. It must have the format
+ * "projects/{project}/topics/{topic}".
+ */
+ public static Builder newBuilder(String topic) {
+ PATH_TEMPLATE.validatedMatch(topic, "topic name must be in valid format");
+ return new Builder(topic);
+ }
+
+ static NotificationInfo fromPb(Notification notificationPb) {
+ Builder builder = newBuilder(notificationPb.getTopic());
+ if (notificationPb.getId() != null) {
+ builder.setGeneratedId(notificationPb.getId());
+ }
+ if (notificationPb.getEtag() != null) {
+ builder.setEtag(notificationPb.getEtag());
+ }
+ if (notificationPb.getCustomAttributes() != null) {
+ builder.setCustomAttributes(notificationPb.getCustomAttributes());
+ }
+ if (notificationPb.getSelfLink() != null) {
+ builder.setSelfLink(notificationPb.getSelfLink());
+ }
+ if (notificationPb.getObjectNamePrefix() != null) {
+ builder.setObjectNamePrefix(notificationPb.getObjectNamePrefix());
+ }
+ if (notificationPb.getTopic() != null) {
+ builder.setTopic(notificationPb.getTopic());
+ }
+ if (notificationPb.getEventTypes() != null) {
+ builder.setEventTypes(notificationPb.getEventTypes());
+ }
+ if (notificationPb.getPayloadFormat() != null) {
+ builder.setPayloadFormat(PayloadFormat.valueOf(notificationPb.getPayloadFormat()));
+ }
+ return builder.build();
+ }
+}
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
index 988f87d39..fa196c90d 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
@@ -21,6 +21,7 @@
import com.google.api.core.InternalExtensionOnly;
import com.google.api.gax.paging.Page;
+import com.google.api.services.storage.model.Notification;
import com.google.auth.ServiceAccountSigner;
import com.google.auth.ServiceAccountSigner.SigningException;
import com.google.cloud.FieldSelector;
@@ -3433,4 +3434,36 @@ List testIamPermissions(
* @throws StorageException upon failure
*/
ServiceAccount getServiceAccount(String projectId);
+
+ /**
+ * Creates a notification with the specified entity on the specified bucket.
+ *
+ * @return the notification that was created.
+ * @throws StorageException upon failure
+ */
+ Notification createNotification(String bucket, NotificationInfo notification);
+
+ /**
+ * Get the notification with the specified name on the specified object.
+ *
+ * @return the notification object that exist on the bucket.
+ * @throws StorageException upon failure
+ */
+ Notification getNotification(String bucket, String notification);
+
+ /**
+ * List the notifications for the provided bucket.
+ *
+ * @return a list of {@link Notification} objects that exist on the bucket.
+ * @throws StorageException upon failure
+ */
+ List listNotifications(String bucket);
+
+ /**
+ * Deletes the notification with the specified name on the specified object.
+ *
+ * @return {@code true} if the notification was deleted, {@code false} if it was not found
+ * @throws StorageException upon failure
+ */
+ boolean deleteNotification(String bucket, String notification);
}
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java
index 0e24521eb..ef46249d0 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java
@@ -36,6 +36,7 @@
import com.google.api.gax.paging.Page;
import com.google.api.services.storage.model.BucketAccessControl;
+import com.google.api.services.storage.model.Notification;
import com.google.api.services.storage.model.ObjectAccessControl;
import com.google.api.services.storage.model.StorageObject;
import com.google.api.services.storage.model.TestIamPermissionsResponse;
@@ -1698,6 +1699,79 @@ public com.google.api.services.storage.model.ServiceAccount call() {
}
}
+ @Override
+ public Notification createNotification(final String bucket, final NotificationInfo notification) {
+ final com.google.api.services.storage.model.Notification notificationPb = notification.toPb();
+ try {
+ return runWithRetries(
+ new Callable() {
+ @Override
+ public com.google.api.services.storage.model.Notification call() {
+ return storageRpc.createNotification(bucket, notificationPb);
+ }
+ },
+ getOptions().getRetrySettings(),
+ EXCEPTION_HANDLER,
+ getOptions().getClock());
+ } catch (RetryHelperException e) {
+ throw StorageException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public Notification getNotification(final String bucket, final String notification) {
+ try {
+ return runWithRetries(
+ new Callable() {
+ @Override
+ public Notification call() {
+ return storageRpc.getNotification(bucket, notification);
+ }
+ },
+ getOptions().getRetrySettings(),
+ EXCEPTION_HANDLER,
+ getOptions().getClock());
+ } catch (RetryHelperException e) {
+ throw StorageException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public List listNotifications(final String bucket) {
+ try {
+ return runWithRetries(
+ new Callable>() {
+ @Override
+ public List call() {
+ return storageRpc.listNotifications(bucket);
+ }
+ },
+ getOptions().getRetrySettings(),
+ EXCEPTION_HANDLER,
+ getOptions().getClock());
+ } catch (RetryHelperException e) {
+ throw StorageException.translateAndThrow(e);
+ }
+ }
+
+ @Override
+ public boolean deleteNotification(final String bucket, final String notification) {
+ try {
+ return runWithRetries(
+ new Callable() {
+ @Override
+ public Boolean call() {
+ return storageRpc.deleteNotification(bucket, notification);
+ }
+ },
+ getOptions().getRetrySettings(),
+ EXCEPTION_HANDLER,
+ getOptions().getClock());
+ } catch (RetryHelperException e) {
+ throw StorageException.translateAndThrow(e);
+ }
+ }
+
private static void addToOptionMap(
StorageRpc.Option option, T defaultValue, Map map) {
addToOptionMap(option, option, defaultValue, map);
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
index e211c0277..97ceafa32 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
@@ -1489,6 +1489,21 @@ public Notification createNotification(String bucket, Notification notification)
}
}
+ @Override
+ public Notification getNotification(String bucket, String notification) {
+ Span span = startSpan(HttpStorageRpcSpans.SPAN_NAME_GET_NOTIFICATION);
+ Scope scope = tracer.withSpan(span);
+ try {
+ return storage.notifications().get(bucket, notification).execute();
+ } catch (IOException ex) {
+ span.setStatus(Status.UNKNOWN.withDescription(ex.getMessage()));
+ throw translate(ex);
+ } finally {
+ scope.close();
+ span.end();
+ }
+ }
+
@Override
public Bucket lockRetentionPolicy(Bucket bucket, Map
+
+ com.google.cloud
+ google-cloud-pubsub
+ 1.106.0
+ test
+
org.easymock
easymock