All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.net.topic.Subscriber Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */
package com.tangosol.net.topic;

import com.tangosol.net.FlowControl;

import com.tangosol.io.ExternalizableLite;
import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;

import com.tangosol.util.ExternalizableHelper;
import com.tangosol.util.Filter;
import com.tangosol.util.function.Remote;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import java.util.concurrent.CompletableFuture;

import java.util.function.Function;

/**
 * A {@link Subscriber} subscribes either directly to a {@link NamedTopic} or to a {@link NamedTopic#getSubscriberGroups() subscriber group} of the {@link NamedTopic}.
 * Each value published to a {@link NamedTopic} is delivered to all of its {@link NamedTopic#getSubscriberGroups() subscriber groups}
 * and direct {@link Subscriber}s. Within each subscriber group, each value is only {@link #receive() received} by one of the {@link Subscriber group members},
 * enabling distributed, parallel processing of the values delivered to the subscriber group.
 * Thus each subscriber group in effect behaves like a queue over the topic data.
 * 

* The factory method {@link NamedTopic#createSubscriber(Subscriber.Option[])} allows one to specify * one or more {@link Subscriber.Option}s to configure the {@link Subscriber}. The {@link Subscriber.Name#of(String)} option * specifies the subscriber group for the {@link Subscriber} to join. If this option is not specified, the * {@link Subscriber} is a direct subscriber to the topic. All Subscriber options and defaults are summarized in a table in {@link Option}. * * @param the type of the value returned to the subscriber * * @author jf/jk/mf 2015.06.03 * @since Coherence 14.1.1 */ public interface Subscriber extends AutoCloseable { /** * Element represents a container for returned values. * * @param the type of value stored in the topic */ interface Element { /** * Return the received value * * @return the received value */ V getValue(); } /** * Receive a value from the topic. If there is no value available then the future will complete according to * the {@link CompleteOnEmpty} option. *

* Note: If the returned future is {@link CompletableFuture#cancel(boolean) cancelled} it is possible that a value * may still be considered by the topic to have been received by this group, while the group would consider this * a lost value. Subscriber implementations will make a best effort to prevent such loss, but it cannot be guaranteed * and thus cancellation is not advisable. * * @return a future which can be used to access the result of this completed operation */ public CompletableFuture> receive(); /** * Return the {@link FlowControl} object governing this subscriber. * * @return the FlowControl object. */ public FlowControl getFlowControl(); /** * Close the Subscriber. *

* Closing a subscriber ensures that no new {@link #receive} requests will be accepted and all pending * receive requests will be completed or safely cancelled. *

* For a direct topic {@link Subscriber}, {@link #close()} enables the release of storage resources for * unconsumed values. *

* For a {@link Subscriber group member}, {@link #close()} indicates that this member has left its corresponding {@link Name group}. * One must actively manage a {@link NamedTopic#getSubscriberGroups() NamedTopic's logical subscriber groups} since their life span * is independent of active {@link Subscriber} group membership. * {@link NamedTopic#destroySubscriberGroup(String)} releases storage and stops accumulating topic values for a subscriber group. */ @Override public void close(); /** * Determine whether this {@link Subscriber} is active. * * @return {@code true} if this {@link Subscriber} is active */ public boolean isActive(); /** * Add an action to be executed when this {@link Subscriber} is closed. * * @param action the action to execute */ public void onClose(Runnable action); // ----- inner interface: Option ------------------------------------ /** * A marker interface to indicate that a class is a valid {@link Option} * for a {@link Subscriber}. *

*

* * * * * * * * * * * * * * * * * * * * * *
Options to use with {@link NamedTopic#createSubscriber(Subscriber.Option...)}
Subscriber OptionDescription
{@link Name#of(String)}Specify subscriber group name. *
For each value delivered to a subscriber group, only one member of the group receives the value.
{@link Filtered#by(Filter)}Only {@link Subscriber#receive() Subscriber.receive()} values matching this Filter. *
Only one Filter per subscription group.
{@link Convert#using(Function)}Convert topic value using provided {@link Function} (or {@link Remote.Function}) prior to {@link Subscriber#receive()}. *
Only one Converter per subscription group.
{@link CompleteOnEmpty#enabled()}When no values left to {@link #receive()}, returned {@link CompletableFuture#get()} returns null Element. *
By default, returned {@link CompletableFuture#get()} blocks until next topic value is available to return.
*

* *

* All members of subscriber group share at most a single {@link Filter} and single {@link Convert Converter}. The last * {@link Subscriber} joining the group and specifying these option(s) are the ones used by all subscriber group members. * Note that when both a {@link Filtered#by(Filter)} and {@link Convert#using(Function)} are specified, the {@link Filter} is * applied first and only {@link NamedTopic} values matching the filter are converted before being * {@link Subscriber#receive() received by the Subscriber(s)}. *

* * @param the type of the value on the topic * @param the type of the value returned to the subscriber */ public interface Option { } // ----- inner interface: Name ------------------------------------------ /** * The Name option is used to specify a subscriber group name. *

* Providing a group name allows multiple subscriber instances to share the * responsibility for processing the contents of the group's durable subcription. * Each item added to the durable subscription will only be received by one member * of the group, whereas each distinct subscriber group for the topic will see * every added item. *

* Naming a subscriber also allows it to outlive its subscriber instances. * For example a group can be created, all instances can terminate and * then later be recreated and pickup exactly where they left off in the * topic. As the groups life is independent of its subscriber instances * the group must be explicitly * {@link NamedTopic#destroySubscriberGroup(String) destroyed} * in order to have the topic stop retaining values for it. *

* If the {@link Name} option is not specified then the subscriber will be * part of an anonymous group populated by no other members and will thus * be ensured to see the full contents of the topic and automatically * destroyed upon being {@link #close closed}, or when the Coherence member * terminates. */ public static class Name implements Option, ExternalizableLite, PortableObject { /** * Default constructor for serialization. */ public Name() { } /** * Construct a new group name. * * @param sName the group name */ protected Name(String sName) { m_sName = sName; } /** * Obtain a {@link Option} that specifies a group name * for a {@link Subscriber}. * * @param sName the group name to use for the {Link Subscriber}. * * @return a {@link Option} that specifies a group name * for a {@link Subscriber} */ public static Name of(String sName) { return new Name<>(sName); } /** * Return the group name. * * @return the group name */ public String getName() { return m_sName; } @Override public void readExternal(DataInput in) throws IOException { m_sName = ExternalizableHelper.readSafeUTF(in); } @Override public void writeExternal(DataOutput out) throws IOException { ExternalizableHelper.writeSafeUTF(out, m_sName); } @Override public void readExternal(PofReader in) throws IOException { m_sName = in.readString(0); } @Override public void writeExternal(PofWriter out) throws IOException { out.writeString(0, m_sName); } /** * The group name. */ private String m_sName; } // ----- inner class: Filtered ------------------------------------------ /** * The Filtered option specifies a filter that will determine which topic values a * subscriber is interested in receiving. Note that all members of a subscriber group * share a single filter. If members join the group using different filters then the last * one to join will set the filter for the group. * * @param the type of the value on the topic */ public static class Filtered implements Option, ExternalizableLite, PortableObject { /** * Default constructor for serialization. */ public Filtered() { } protected Filtered(Filter filter) { m_filter = filter; } /** * Return the option's filter. * * @return the filter */ public Filter getFilter() { return m_filter; } /** * Return a Filtered option with the specified filter. * * @param filter the filter * * @return the Filtered option */ public static Filtered by(Filter filter) { return new Filtered<>(filter); } @Override public void readExternal(DataInput in) throws IOException { m_filter = ExternalizableHelper.readObject(in); } @Override public void writeExternal(DataOutput out) throws IOException { ExternalizableHelper.writeObject(out, m_filter); } @Override public void readExternal(PofReader in) throws IOException { m_filter = in.readObject(0); } @Override public void writeExternal(PofWriter out) throws IOException { out.writeObject(0, m_filter); } /** * The filter. */ private Filter m_filter; } // ----- inner class: Convert ------------------------------------------ /** * The Convert option specifies a {@link Function} that will convert topic values that * a subscriber is interested in receiving prior to sending them to the subscriber. * Note that all members of a subscriber group share a single converter. If members join the group using different * converter then the last one to join will set the converter function for the group. * * @param the type of the topic value * @param the type of the value returned to the subscriber */ public static class Convert implements Option, ExternalizableLite, PortableObject { /** * Default constructor for serialization. */ public Convert() { } protected Convert(Function function) { m_function = function; } /** * Return the option's converter function. * * @return the converter function */ public Function getFunction() { return m_function; } /** * Return a Convert option with the specified function. * * @param function the converter function * * @return the Filtered option */ public static Convert using(Function function) { return new Convert<>(function); } /** * Return a Convert option with the specified function. * * @param function the converter function * * @return the Filtered option */ public static Convert using(Remote.Function function) { return using((Function) function); } @Override public void readExternal(DataInput in) throws IOException { m_function = ExternalizableHelper.readObject(in); } @Override public void writeExternal(DataOutput out) throws IOException { ExternalizableHelper.writeObject(out, m_function); } @Override public void readExternal(PofReader in) throws IOException { m_function = in.readObject(0); } @Override public void writeExternal(PofWriter out) throws IOException { out.writeObject(0, m_function); } /** * The filter. */ private Function m_function; } // ----- inner class: CompleteOnEmpty ------------------------------- /** * The CompleteOnEmpty option indicates that the {@link CompletableFuture} returned * from the {@link #receive} operation should complete with a null {@link Element} * upon identifying that the topic is or has become empty. Without this option the * future will not complete until a new value becomes available. It is supported for this * option to differ between members of the same subscriber group. */ public static class CompleteOnEmpty implements Option, ExternalizableLite, PortableObject { /** * Default constructor for serialization. */ public CompleteOnEmpty() {} @Override public void readExternal(DataInput in) throws IOException { } @Override public void writeExternal(DataOutput out) throws IOException { } @Override public void readExternal(PofReader in) throws IOException { } @Override public void writeExternal(PofWriter out) throws IOException { } /** * Obtain the Option indicating futures should complete if the topic is empty. * * @return the option */ @SuppressWarnings("unchecked") public static CompleteOnEmpty enabled() { return INSTANCE; } /** * The CompleteOnEmpty singleton. */ protected static final CompleteOnEmpty INSTANCE = new CompleteOnEmpty(); } }