diff --git a/gcloud-java-pubsub/src/main/java/com/google/cloud/pubsub/Message.java b/gcloud-java-pubsub/src/main/java/com/google/cloud/pubsub/Message.java index c8d5ec7500da..b83e5a6296f6 100644 --- a/gcloud-java-pubsub/src/main/java/com/google/cloud/pubsub/Message.java +++ b/gcloud-java-pubsub/src/main/java/com/google/cloud/pubsub/Message.java @@ -122,7 +122,7 @@ public abstract static class Builder { abstract Builder publishTime(long publishTime); /** - * Creates a topic object. + * Creates a message object. */ public abstract Message build(); } diff --git a/gcloud-java-pubsub/src/main/java/com/google/cloud/pubsub/PushConfig.java b/gcloud-java-pubsub/src/main/java/com/google/cloud/pubsub/PushConfig.java index 61b64a07b36b..b8e9fae3f578 100644 --- a/gcloud-java-pubsub/src/main/java/com/google/cloud/pubsub/PushConfig.java +++ b/gcloud-java-pubsub/src/main/java/com/google/cloud/pubsub/PushConfig.java @@ -27,7 +27,16 @@ import java.util.Objects; /** - * PubSub subscription push configuration. + * Google Cloud Pub/Sub configuration for a push subscription. + * + *

In a push subscription, the Pub/Sub server sends a request to the subscriber application. A + * {@code PushConfig} object can be used to configure the application endpoint. The subscriber's + * HTTP response serves as an implicit acknowledgement: a success response indicates that the + * message has been succesfully processed and the Pub/Sub system can delete it from the + * subscription; a non-success response indicates that the Pub/Sub server should resend it + * (implicit "nack"). + * + * @see Subscriber Guide */ public final class PushConfig implements Serializable { @@ -36,34 +45,97 @@ public final class PushConfig implements Serializable { private final String endpoint; private final ImmutableMap attributes; + /** + * Builder for {@code PushConfig} objects. + */ public static final class Builder { private String endpoint; - private final Map attributes = new HashMap<>(); + private Map attributes = new HashMap<>(); private Builder() { } - public Builder endPoint(String endpoint) { + /** + * Sets the URL locating the endpoint to which messages should be pushed. For example, an + * endpoint might use {@code https://example.com/push}. + */ + public Builder endpoint(String endpoint) { this.endpoint = checkNotNull(endpoint); return this; } + /** + * Adds an API-supported attribute that can be used to control different aspects of the message + * delivery. + * + *

The currently supported attribute is {@code x-goog-version}, which can be used to change + * the format of the push message. This attribute indicates the version of the data expected by + * the endpoint. The endpoint version is based on the version of the Pub/Sub API. Possible + * values for this attribute are: + *

+ * + *

If the {@code x-goog-version} attribute is not present when a subscription is created (see + * {@link PubSub#create(SubscriptionInfo)} and {@link PubSub#createAsync(SubscriptionInfo)}), it + * will default to {@code v1}. If it is not present when modifying the push config (see + * {@link PubSub#replacePushConfig(String, PushConfig)} and + * {@link PubSub#replacePushConfigAsync(String, PushConfig)}), its value will not be changed. + * + * @see Message Format + */ public Builder addAttribute(String name, String value) { attributes.put(name, value); return this; } + /** + * Sets the API-supported attributes that can be used to control different aspects of the + * message delivery. + * + *

The currently supported attribute is {@code x-goog-version}, which can be used to change + * the format of the push message. This attribute indicates the version of the data expected by + * the endpoint. The endpoint version is based on the version of the Pub/Sub API. Possible + * values for this attribute are: + *

+ * + *

If the {@code x-goog-version} attribute is not present when a subscription is created (see + * {@link PubSub#create(SubscriptionInfo)} and {@link PubSub#createAsync(SubscriptionInfo)}), it + * will default to {@code v1}. If it is not present when modifying the push config (see + * {@link PubSub#replacePushConfig(String, PushConfig)} and + * {@link PubSub#replacePushConfigAsync(String, PushConfig)}), its value will not be changed. + * + * @see Message Format + */ + public Builder attributes(Map attributes) { + this.attributes = new HashMap<>(attributes); + return this; + } + + /** + * Removes an API-supported attribute. + */ public Builder removeAttribute(String name) { attributes.remove(name); return this; } + /** + * Clears all API-supported attributes. + */ public Builder clearAttributes() { attributes.clear(); return this; } + /** + * Creates a {@code PushConfig} object. + */ public PushConfig build() { return new PushConfig(this); } @@ -74,24 +146,49 @@ private PushConfig(Builder builder) { attributes = ImmutableMap.copyOf(builder.attributes); } + /** + * Returns the URL locating the endpoint to which messages should be pushed. For example, an + * endpoint might use {@code https://example.com/push}. + */ public String endpoint() { return endpoint; } + /** + * Returns the API-supported attributes that can be used to control different aspects of the + * message delivery. + * + *

The currently supported attribute is {@code x-goog-version}, which can be used to change + * the format of the push message. This attribute indicates the version of the data expected by + * the endpoint. The endpoint version is based on the version of the Pub/Sub API. Possible + * values for this attribute are: + *

+ * + *

If the {@code x-goog-version} attribute is not present when a subscription is created (see + * {@link PubSub#create(SubscriptionInfo)} and {@link PubSub#createAsync(SubscriptionInfo)}), it + * will default to {@code v1}. If it is not present when modifying the push config (see + * {@link PubSub#replacePushConfig(String, PushConfig)} and + * {@link PubSub#replacePushConfigAsync(String, PushConfig)}), its value will not be changed. + * + * @see Message Format + */ public Map attributes() { return attributes; } @Override - public boolean equals(Object o) { - if (this == o) { + public boolean equals(Object obj) { + if (this == obj) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!(obj instanceof PushConfig)) { return false; } - PushConfig that = (PushConfig) o; - return Objects.equals(endpoint, that.endpoint) && Objects.equals(attributes, that.attributes); + PushConfig other = (PushConfig) obj; + return Objects.equals(endpoint, other.endpoint) && Objects.equals(attributes, other.attributes); } @Override @@ -107,28 +204,57 @@ public String toString() { .toString(); } + /** + * Returns a builder for the {@code PushConfig} object. + */ public Builder toBuilder() { return builder(endpoint, attributes); } + /** + * Creates a {@code PushConfig} object given the push endpoint. + * + * @param endpoint the URL locating the endpoint to which messages should be pushed. For example, + * an endpoint might use {@code https://example.com/push}. + */ public static PushConfig of(String endpoint) { return builder(endpoint).build(); } + /** + * Creates a {@code PushConfig} object given the push endpoint and the API-supported attributes + * that can be used to control different aspects of the message delivery. + * + * @param endpoint the URL locating the endpoint to which messages should be pushed. For example, + * an endpoint might use {@code https://example.com/push}. + * @param attributes API supported attributes used to control message delivery. See + * {@link Builder#attributes(Map)} for more details. + */ public static PushConfig of(String endpoint, Map attributes) { return builder(endpoint, attributes).build(); } - public static Builder builder(String endPoint) { - return new Builder().endPoint(endPoint); + /** + * Creates a builder for {@code PushConfig} objects given the push endpoint. + * + * @param endpoint the URL locating the endpoint to which messages should be pushed. For example, + * an endpoint might use {@code https://example.com/push}. + */ + public static Builder builder(String endpoint) { + return new Builder().endpoint(endpoint); } + /** + * Creates a builder for {@code PushConfig} objects given the push endpoint and the API-supported + * attributes that can be used to control different aspects of the message delivery. + * + * @param endpoint the URL locating the endpoint to which messages should be pushed. For example, + * an endpoint might use {@code https://example.com/push}. + * @param attributes API supported attributes used to control message delivery. See + * {@link Builder#attributes(Map)} for more details. + */ public static Builder builder(String endpoint, Map attributes) { - Builder builder = builder(endpoint); - for (Map.Entry entry : attributes.entrySet()) { - builder.addAttribute(entry.getKey(), entry.getValue()); - } - return builder; + return builder(endpoint).attributes(attributes); } com.google.pubsub.v1.PushConfig toPb() { diff --git a/gcloud-java-pubsub/src/test/java/com/google/cloud/pubsub/MessageTest.java b/gcloud-java-pubsub/src/test/java/com/google/cloud/pubsub/MessageTest.java index 3b94bae0d958..c6b177662a9b 100644 --- a/gcloud-java-pubsub/src/test/java/com/google/cloud/pubsub/MessageTest.java +++ b/gcloud-java-pubsub/src/test/java/com/google/cloud/pubsub/MessageTest.java @@ -57,7 +57,11 @@ public void testToBuilder() { .build(); assertEquals("newPayload", message.payloadAsString()); assertEquals(ImmutableMap.of("key1", "value1"), message.attributes()); - message = MESSAGE.toBuilder().payload(PAYLOAD_STRING).attributes(ATTRIBUTES).build(); + message = message.toBuilder() + .payload(PAYLOAD_STRING) + .removeAttribute("key1") + .attributes(ATTRIBUTES) + .build(); compareMessage(MESSAGE, message); } diff --git a/gcloud-java-pubsub/src/test/java/com/google/cloud/pubsub/PushConfigTest.java b/gcloud-java-pubsub/src/test/java/com/google/cloud/pubsub/PushConfigTest.java new file mode 100644 index 000000000000..496c10d04938 --- /dev/null +++ b/gcloud-java-pubsub/src/test/java/com/google/cloud/pubsub/PushConfigTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * 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.pubsub; + +import static org.junit.Assert.assertEquals; + +import com.google.common.collect.ImmutableMap; + +import org.junit.Test; + +import java.util.Map; + +public class PushConfigTest { + + private static final String ENDPOINT = "https://example.com/push"; + private static final Map ATTRIBUTES = + ImmutableMap.of("key1", "value1", "key2", "value2"); + private static final PushConfig PUSH_CONFIG = PushConfig.builder(ENDPOINT, ATTRIBUTES).build(); + + @Test + public void testToBuilder() { + comparePushConfig(PUSH_CONFIG, PUSH_CONFIG.toBuilder().build()); + PushConfig pushConfig = PUSH_CONFIG.toBuilder() + .endpoint("https://example2.com/push") + .clearAttributes() + .addAttribute("key1", "value1") + .build(); + assertEquals("https://example2.com/push", pushConfig.endpoint()); + assertEquals(ImmutableMap.of("key1", "value1"), pushConfig.attributes()); + pushConfig = pushConfig.toBuilder() + .endpoint(ENDPOINT) + .removeAttribute("key1") + .attributes(ATTRIBUTES) + .build(); + comparePushConfig(PUSH_CONFIG, pushConfig); + } + + @Test + public void testBuilder() { + assertEquals(ENDPOINT, PUSH_CONFIG.endpoint()); + assertEquals(ATTRIBUTES, PUSH_CONFIG.attributes()); + PushConfig pushConfig = PushConfig.builder("https://example2.com/push") + .endpoint(ENDPOINT) + .attributes(ATTRIBUTES) + .clearAttributes() + .addAttribute("key1", "value1") + .addAttribute("key2", "value2") + .build(); + assertEquals(ENDPOINT, pushConfig.endpoint()); + assertEquals(ATTRIBUTES, pushConfig.attributes()); + comparePushConfig(PUSH_CONFIG, pushConfig); + } + + @Test + public void testOf() { + PushConfig pushConfig = PushConfig.of(ENDPOINT); + assertEquals(ENDPOINT, pushConfig.endpoint()); + assertEquals(ImmutableMap.of(), pushConfig.attributes()); + pushConfig = PushConfig.of(ENDPOINT, ATTRIBUTES); + assertEquals(ENDPOINT, pushConfig.endpoint()); + assertEquals(ATTRIBUTES, pushConfig.attributes()); + comparePushConfig(PUSH_CONFIG, pushConfig); + } + + @Test + public void testToAndFromPb() { + comparePushConfig(PUSH_CONFIG, PushConfig.fromPb(PUSH_CONFIG.toPb())); + } + + @Test + public void testToAndFromPbIncomplete() { + PushConfig pushConfig = PushConfig.of(ENDPOINT); + comparePushConfig(pushConfig, PushConfig.fromPb(pushConfig.toPb())); + } + + private void comparePushConfig(PushConfig expected, PushConfig value) { + assertEquals(expected, value); + assertEquals(expected.endpoint(), value.endpoint()); + assertEquals(expected.attributes(), value.attributes()); + assertEquals(expected.hashCode(), value.hashCode()); + } +}