package com.atlassian.bitbucket.topic;

import com.atlassian.bitbucket.event.cluster.ClusterNodeEvent;

import javax.annotation.Nonnull;
import java.io.Serializable;

/**
 * Provides a mechanism for publishing messages to multiple subscribers, both local and cluster-wide. When a listener
 * subscribes to a topic, it receives all messages published to that topic from any node until the listener unsubscribes.
 * <p>
 * Messages are delivered in the order they were published on the node they were published on. If node N publishes
 * messages m1, m2..mn, all listeners receive messages m1, m2..mn in order.
 * <p>
 * Messages are <em>not</em> durable and message delivery is guaranteed only to the listeners that were reachable at
 * the time a message is published. In the case of network partitions, listeners may miss messages. Plugins that rely
 * on {@code TopicService} to handle cluster coherency are encouraged to also listen for the various
 * {@link ClusterNodeEvent cluster node events} to handle nodes joining, rejoining and
 * leaving the cluster.
 */
public interface TopicService {

    /**
     * Publishes a message to all (both local and remote) listeners of the topic
     *
     * @param topic the topic to publish to
     * @param message the message
     */
    <T extends Serializable> void publish(@Nonnull String topic, @Nonnull T message);

    /**
     * Subscribes a provided listener to a topic. The listener will receive callbacks for every message published to
     * the topic after the listener was subscribed
     *
     * @param topic the topic to subscribe to
     * @param listener the listener that should receive callbacks when a message is published to the topic
     * @return the subscription ID, used to {@link #unsubscribe(String) unsubscribe}.
     */
    @Nonnull
    <T extends Serializable> String subscribe(@Nonnull String topic, @Nonnull TopicListener<T> listener);

    /**
     * Unsubscribes a listener. The listener will not receive any more messages the topic.
     *
     * @param subscriptionId the subscription ID that was returned by {@link #subscribe(String, TopicListener)}
     * @return {@code true} if the listener was successfully unsubscribed, otherwise {@code false}
     */
    boolean unsubscribe(@Nonnull String subscriptionId);
}
