com.pushtechnology.diffusion.client.features.control.topics.SubscriptionControl Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2023 DiffusionData Ltd., All Rights Reserved.
*
* Use is subject to license terms.
*
* NOTICE: All information contained herein is, and remains the
* property of Push Technology. The intellectual and technical
* concepts contained herein are proprietary to Push Technology and
* may be covered by U.S. and Foreign Patents, patents in process, and
* are protected by trade secret or copyright law.
*******************************************************************************/
package com.pushtechnology.diffusion.client.features.control.topics;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.pushtechnology.diffusion.client.callbacks.Callback;
import com.pushtechnology.diffusion.client.callbacks.ContextCallback;
import com.pushtechnology.diffusion.client.callbacks.Registration;
import com.pushtechnology.diffusion.client.callbacks.Stream;
import com.pushtechnology.diffusion.client.features.HandlerConflictException;
import com.pushtechnology.diffusion.client.features.InvalidFilterException;
import com.pushtechnology.diffusion.client.features.NoSuchSessionException;
import com.pushtechnology.diffusion.client.features.TopicTreeHandler;
import com.pushtechnology.diffusion.client.features.control.clients.ClientControl.SessionPropertiesListener;
import com.pushtechnology.diffusion.client.session.Feature;
import com.pushtechnology.diffusion.client.session.PermissionsException;
import com.pushtechnology.diffusion.client.session.Session;
import com.pushtechnology.diffusion.client.session.SessionClosedException;
import com.pushtechnology.diffusion.client.session.SessionException;
import com.pushtechnology.diffusion.client.session.SessionId;
import com.pushtechnology.diffusion.client.topics.TopicSelector;
import com.pushtechnology.diffusion.client.topics.TopicSelectors;
import com.pushtechnology.diffusion.client.topics.details.TopicType;
import com.pushtechnology.diffusion.client.types.ErrorReport;
import com.pushtechnology.diffusion.client.types.GlobalPermission;
import com.pushtechnology.diffusion.client.types.PathPermission;
/**
* This feature allows a session to subscribe or unsubscribe other sessions to
* topics. It also provides a mechanism for handling requests to subscribe to
* routing topics (deprecated).
*
* Requests to subscribe sessions to topics can be submitted at any time even if
* the topics do not exist at the server. {@link TopicSelector Topic selectors}
* are used on subscription to match against topics at the server. The session
* will become subscribed to any topics that exist at the server that match the
* selector (unless they are already subscribed, or the session has insufficient
* permission). The subscription request is also retained at the server so that
* if any newly created topics match the selector, the session will then become
* subscribed to it (unless a subsequent unsubscription cancels it).
*
* Specific sessions may be subscribed/unsubscribed if the {@link SessionId} is
* known.
*
* Subscriptions may also be requested using 'session filters' (see
* {@link Session} for a full description of session filters), where all
* sessions that satisfy a particular filter expression will be
* subscribed/unsubscribed. The filter is only evaluated once against the
* current sessions that exist at the time - it is not retained and applied to
* any sessions that are created later. In order to be notified of new sessions
* as they are created {@link SessionPropertiesListener session properties
* listeners} can be used and those sessions subscribed as required based upon
* their session properties.
*
*
* A handler for routing topics belonging to a branch of the topic tree can be
* added using
* {@link #addRoutingSubscriptionHandler(String, SubscriptionControl.RoutingSubscriptionRequest.RoutingHandler)
* addRoutingSubscriptionHandler()}. When another session subscribes to one of
* the routing topics, the handler will be called to determine the appropriate
* source topic.
*
*
Access control
To subscribe other sessions to topics, a session must
* have {@link GlobalPermission#MODIFY_SESSION MODIFY_SESSION} permission, and
* {@link PathPermission#SELECT_TOPIC SELECT_TOPIC} permission for the path
* prefix of the topic selector used for subscription. The subscribed sessions
* will only be subscribed to matching topics for which they have
* {@link PathPermission#READ_TOPIC READ_TOPIC} permission.
*
* To unsubscribe other sessions, a session must have
* {@link GlobalPermission#MODIFY_SESSION MODIFY_SESSION} permission.
*
* To register a {@link #addRoutingSubscriptionHandler routing subscription
* handler} the session needs {@link GlobalPermission#VIEW_SESSION
* VIEW_SESSION}, {@link GlobalPermission#MODIFY_SESSION MODIFY_SESSION} and
* {@link GlobalPermission#REGISTER_HANDLER REGISTER_HANDLER} permissions.
*
* When handling a subscription request to a routing topic via a routing handler
* the routing session needs {@link PathPermission#READ_TOPIC READ_TOPIC}
* permission to both the routing topic being subscribed to and the target topic
* that is assigned.
*
* Operations that identify sessions using a session filter require the
* {@link GlobalPermission#VIEW_SESSION VIEW_SESSION} permission.
*
*
Accessing the feature
This feature may be obtained from a
* {@link Session session} as follows:
*
*
*
* SubscriptionControl subsControl = session.feature(SubscriptionControl.class);
*
*
*
* @author DiffusionData Limited
* @since 5.0
*/
public interface SubscriptionControl extends Feature {
/**
* Adds a handler for {@link TopicType#ROUTING routing} topics that belong
* to a branch of the topic tree. When another session subscribes to one of
* the routing topics, the handler will be called to determine the
* appropriate source topic.
*
*
* For each subscription to the routing topic, the server will select a
* handler registered for the most specific branch. If multiple handlers are
* registered for the same branch, the server will select one of them
* arbitrarily.
*
* @param topicPath identifies the branch of the topic tree to associate the
* handler with
*
* @param handler the handler to use for routing topics at or below the
* specified path (unless there is a handler registered for a more
* specific topic path)
*
* @return a CompletableFuture that completes when the handler is registered
* with the server.
*
*
* If registration was successful, the CompletableFuture will
* complete successfully with a {@link Registration} which can be
* used to unregister the handler.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link HandlerConflictException} – if the session has
* already registered a routing subscription handler for
* {@code topicPath};
*
*
- {@link PermissionsException} – if the session does
* not have {@code REGISTER_HANDLER} permission;
*
*
- {@link PermissionsException} – if the session does
* not have {@code VIEW_SESSION} permission;
*
*
- {@link PermissionsException} – if the session does
* not have {@code MODIFY_SESSION} permission;
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @since 6.0
* @deprecated since 6.7
*
* Routing topics are deprecated. The more powerful
* {@link SessionTrees} feature should be used in their place.
*/
@Deprecated
CompletableFuture addRoutingSubscriptionHandler(
String topicPath,
RoutingSubscriptionRequest.RoutingHandler handler);
/**
* Adds a handler for {@link TopicType#ROUTING routing} topics that belong
* to a branch of the topic tree. When another session subscribes to one of
* the routing topics, the handler will be called to determine the
* appropriate source topic.
*
*
* The CompletableFuture-based alternative
* {@link SubscriptionControl#addRoutingSubscriptionHandler(String, com.pushtechnology.diffusion.client.features.control.topics.SubscriptionControl.RoutingSubscriptionRequest.RoutingHandler)
* addRoutingSubscriptionHandler(String, RoutingHandler)} should be
* preferred since it provides better error reporting.
*
*
* For each subscription to the routing topic, the server will select a
* handler registered for the most specific branch. If multiple handlers are
* registered for the same branch, the server will select one of them
* arbitrarily.
*
* @param topicPath identifies the branch of the topic tree to associate the
* handler with
*
* @param handler the handler to use for routing topics at or below the
* specified path (unless there is a handler registered for a
* more specific topic path)
*
* @deprecated since 6.7
*
* Routing topics are deprecated. The more powerful
* {@link SessionTrees} feature should be used in their place.
*/
@Deprecated
void addRoutingSubscriptionHandler(
String topicPath,
RoutingSubscriptionRequest.Handler handler);
/**
* Subscribe another session to topics.
*
*
* This is equivalent to calling
* {@link #subscribe(SessionId, TopicSelector)} with a selector parsed using
* {@link TopicSelectors#parse(String)}.
*
* @param sessionId identifies the session to subscribe
*
* @param topics the topics to subscribe to specified as a
* {@link TopicSelector} expression
*
* @return a CompletableFuture that completes when the server has processed
* the subscription request.
*
*
* If the subscription was accepted, the CompletableFuture will
* complete successfully. The result type is any rather than Void
* to provide forward compatibility with future iterations of this
* API that may provide a non-null result with a more specific
* result type.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link PermissionsException} – if the calling
* session does not have {@code MODIFY_SESSION} permission;
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code SELECT_TOPIC} permission for the
* path prefix of the selector expression ;
*
*
- {@link NoSuchSessionException} – if there is no session
* with the given {@code sessionId};
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
* @since 6.0
*/
CompletableFuture> subscribe(
SessionId sessionId,
String topics)
throws IllegalArgumentException;
/**
* Subscribe another session to topics.
*
*
* New subscriptions will be established for existing topics that match the
* provided topic selector and for which the subscribed session has
* {@code READ_TOPIC} permission. The topic selector will be added to the
* topic selections of the subscribed session, and re-evaluated when new
* topics are added or the session's security roles change.
*
*
* A session that does not have {@code SELECT_TOPIC} permission for a topic
* cannot subscribe directly, but can be subscribed indirectly using this
* method.
*
* @param sessionId identifies the session to subscribe
*
* @param topics identifies the topics to subscribe to
*
* @return a CompletableFuture that completes when the server has processed
* the subscription request.
*
*
* If the subscription was accepted, the CompletableFuture will
* complete successfully. The result type is any rather than Void
* to provide forward compatibility with future iterations of this
* API that may provide a non-null result with a more specific
* result type.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link PermissionsException} – if the calling
* session does not have {@code MODIFY_SESSION} permission;
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code SELECT_TOPIC} permission for the
* path prefix of the selector expression ;
*
*
- {@link NoSuchSessionException} – if there is no session
* with the given {@code sessionId};
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
* @since 6.0
*/
CompletableFuture> subscribe(
SessionId sessionId,
TopicSelector topics);
/**
* Subscribe another session to topics.
*
*
* This is equivalent to calling
* {@link #subscribe(SessionId, TopicSelector, SubscriptionCallback)} with a
* selector parsed using {@link TopicSelectors#parse(String)}.
*
* @param sessionId identifies the session to subscribe
*
* @param topics the topics to subscribe to specified as a
* {@link TopicSelector} expression
*
* @param callback provides callback methods to indicate success or failure
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void subscribe(
SessionId sessionId,
String topics,
SubscriptionCallback callback)
throws IllegalArgumentException;
/**
* Subscribe another session to topics.
*
*
* New subscriptions will be established for existing topics that match the
* provided topic selector and for which the subscribed session has
* {@code READ_TOPIC} permission. The topic selector will be added to the
* topic selections of the subscribed session, and re-evaluated when new
* topics are added or the session's security roles change.
*
*
* A session that does not have {@code SELECT_TOPIC} permission for a topic
* cannot subscribe directly, but can be subscribed indirectly using this
* method.
*
* @param sessionId identifies the session to subscribe
*
* @param topics identifies the topics to subscribe to
*
* @param callback provides callback methods to indicate success or failure
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void subscribe(
SessionId sessionId,
TopicSelector topics,
SubscriptionCallback callback);
/**
* Subscribe another session to topics.
*
*
* This is equivalent to calling
* {@link #subscribe(SessionId, TopicSelector, Object, SubscriptionContextCallback)}
* with a selector parsed using {@link TopicSelectors#parse(String)}.
*
* @param sessionId identifies the session to subscribe
*
* @param topics the topics to subscribe to specified as a
* {@link TopicSelector} expression
*
* @param context passed to the callback with the reply to allow requests
* and replies to be correlated. The caller may use any convenient
* object reference, including {@code null}
*
* @param callback provides callback methods to indicate success or failure
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @param context object type
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void subscribe(
SessionId sessionId,
String topics,
C context,
SubscriptionContextCallback callback)
throws IllegalArgumentException;
/**
* Subscribe another session to topics.
*
*
* New subscriptions will be established for existing topics that match the
* provided topic selector and for which the subscribed session has
* {@code READ_TOPIC} permission. The topic selector will be added to the
* topic selections of the subscribed session, and re-evaluated when new
* topics are added or the session's security roles change.
*
*
* A session that does not have {@code SELECT_TOPIC} permission for a topic
* cannot subscribe directly, but can be subscribed indirectly using this
* method.
*
* @param sessionId identifies the session to subscribe
*
* @param topics identifies the topics to subscribe to
*
* @param context passed to the callback with the reply to allow requests
* and replies to be correlated. The caller may use any convenient
* object reference, including {@code null}
*
* @param callback provides callback methods to indicate success or failure
*
* @param context object type
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void subscribe(
SessionId sessionId,
TopicSelector topics,
C context,
SubscriptionContextCallback callback);
/**
* Unsubscribe another session from topics.
*
*
* This is equivalent to calling
* {@link #unsubscribe(SessionId, TopicSelector)} with a selector parsed
* using {@link TopicSelectors#parse(String)}.
*
* @param sessionId identifies the session to unsubscribe
*
* @param topics the topics to unsubscribe specified as a
* {@link TopicSelector} expression
*
* @return a CompletableFuture that completes when the server has processed
* the unsubscription request.
*
*
* If the unsubscription was accepted, the CompletableFuture will
* complete successfully. The result type is any rather than Void
* to provide forward compatibility with future iterations of this
* API that may provide a non-null result with a more specific
* result type.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link PermissionsException} – if the calling
* session does not have {@code MODIFY_SESSION} permission;
*
*
- {@link NoSuchSessionException} – if there is no session
* with the given {@code sessionId};
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
* @since 6.0
*/
CompletableFuture> unsubscribe(
SessionId sessionId,
String topics)
throws IllegalArgumentException;
/**
* Unsubscribe another session from topics.
*
* @param sessionId identifies the session to unsubscribe
*
* @param topics the topics to unsubscribe from
*
* @return a CompletableFuture that completes when the server has processed
* the unsubscription request.
*
*
* If the unsubscription was accepted, the CompletableFuture will
* complete successfully. The result type is any rather than Void
* to provide forward compatibility with future iterations of this
* API that may provide a non-null result with a more specific
* result type.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link PermissionsException} – if the calling
* session does not have {@code MODIFY_SESSION} permission;
*
*
- {@link NoSuchSessionException} – if there is no session
* with the given {@code sessionId};
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
* @since 6.0
*/
CompletableFuture> unsubscribe(
SessionId sessionId,
TopicSelector topics);
/**
* Unsubscribe another session from topics.
*
*
* This is equivalent to calling
* {@link #unsubscribe(SessionId, TopicSelector, SubscriptionCallback)}
* with a selector parsed using {@link TopicSelectors#parse(String)}.
*
* @param sessionId identifies the session to unsubscribe
*
* @param topics the topics to unsubscribe specified as a
* {@link TopicSelector} expression
*
* @param callback provides callback methods indicating the status of this
* operation
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void unsubscribe(
SessionId sessionId,
String topics,
SubscriptionCallback callback)
throws IllegalArgumentException;
/**
* Unsubscribe another session from topics.
*
* @param sessionId identifies the session to unsubscribe
*
* @param topics the topics to unsubscribe from
*
* @param callback provides callback methods indicating the status of this
* operation
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void unsubscribe(
SessionId sessionId,
TopicSelector topics,
SubscriptionCallback callback);
/**
* Unsubscribe another session from topics.
*
*
* This is equivalent to calling
* {@link #unsubscribe(SessionId, TopicSelector, Object, SubscriptionContextCallback)}
* with a selector parsed using {@link TopicSelectors#parse(String)}.
*
* @param sessionId identifies the session to unsubscribe
*
* @param topics the topics to unsubscribe specified as a
* {@link TopicSelector} expression
*
* @param context passed to the callback with the reply to allow requests
* and replies to be correlated. The caller may use any convenient
* object reference, including {@code null}
*
* @param callback provides callback methods indicating the status of this
* operation
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @param context object type
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void unsubscribe(
SessionId sessionId,
String topics,
C context,
SubscriptionContextCallback callback)
throws IllegalArgumentException;
/**
* Unsubscribe another session from topics.
*
* @param sessionId identifies the session to unsubscribe
*
* @param topics the topics to unsubscribe from
*
* @param context passed to the callback with the reply to allow requests
* and replies to be correlated. The caller may use any convenient
* object reference, including {@code null}
*
* @param callback provides callback methods indicating the status of this
* operation
*
* @param context object type
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void unsubscribe(
SessionId sessionId,
TopicSelector topics,
C context,
SubscriptionContextCallback callback);
/**
* Callback interface to receive status notifications for subscription and
* unsubscription operations.
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
interface SubscriptionCallback extends
com.pushtechnology.diffusion.client.features.Callback {
/**
* Called to indicate that the requested operation has been processed by
* the server.
*/
void onComplete();
/**
* Default implementation of {@link SubscriptionCallback}.
*
* This simply logs onComplete calls at 'debug' level. This method may
* be overridden to perform more specific processing.
*/
class Default
extends
com.pushtechnology.diffusion.client.features.Callback.Default
implements SubscriptionCallback {
private static final Logger LOG =
getLogger(SubscriptionCallback.Default.class);
@Override
public void onComplete() {
LOG.debug(
"{} - Subscription/Unsubscription complete",
this);
}
}
}
/**
* Contextual callback interface to receive status notifications for
* subscription and unsubscription operations.
*
*
* Use this alternative to {@link SubscriptionCallback} to associate some
* arbitrary context object with each call.
*
* @param context object type
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
interface SubscriptionContextCallback extends
com.pushtechnology.diffusion.client.features.ContextCallback {
/**
* Called to indicate that the requested operation has been processed by
* the server.
*
* @param context the context object supplied when making the call. May
* be {@code null}.
*/
void onComplete(C context);
/**
* Default implementation of {@link SubscriptionContextCallback}.
*
* This simply logs onComplete calls at 'debug' level. This method may
* be overridden to perform more specific processing.
*
* @param context object type
*/
class Default
extends
com.pushtechnology.diffusion.client.features.ContextCallback.Default
implements SubscriptionContextCallback {
private static final Logger LOG =
getLogger(SubscriptionContextCallback.Default.class);
@Override
public void onComplete(
C context) {
LOG.debug(
"{} - Subscription/Unsubscription complete, context={}",
this,
context);
}
}
}
/**
* Subscribe sessions that satisfy a given session filter to topics.
*
*
* This is equivalent to calling
* {@link #subscribeByFilter(String, TopicSelector)} with a selector parsed
* using {@link TopicSelectors#parse(String)}.
*
* @param filter the session filter expression
*
* @param topics the topics to subscribe to specified as a
* {@link TopicSelector} expression
*
* @return a CompletableFuture that completes when the server has processed
* the subscription request.
*
*
* If the subscription was accepted, the CompletableFuture will
* complete successfully with a {@link SubscriptionByFilterResult}.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link InvalidFilterException} – if the filter is
* invalid;
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code MODIFY_SESSION} and
* {@code VIEW_SESSION} global permissions;
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code SELECT_TOPIC} permission for the
* path prefix of the selector expression;
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @since 6.0
*/
CompletableFuture subscribeByFilter(
String filter,
String topics)
throws IllegalArgumentException;
/**
* Subscribe sessions that satisfy a given session filter to topics.
*
*
* For each session that matches the filter, new subscriptions will be
* established for existing topics that match the provided topic selector
* and for which the sessions has {@code READ_TOPIC} permission. The topic
* selector will be added to the topic selections of the subscribed session,
* and re-evaluated when new topics are added or the session's security
* roles change.
*
*
* A session that does not have {@code SELECT_TOPIC} permission for a topic
* cannot subscribe directly, but can be subscribed indirectly using this
* method.
*
* @param filter the session filter expression
*
* @param topics the topics to subscribe to specified as a
* {@link TopicSelector} expression
*
* @return a CompletableFuture that completes when the server has processed
* the subscription request.
*
*
* If the subscription was accepted, the CompletableFuture will
* complete successfully with a {@link SubscriptionByFilterResult}.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link InvalidFilterException} – if the filter is
* invalid;
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code MODIFY_SESSION} and
* {@code VIEW_SESSION} permissions;
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code SELECT_TOPIC} permission for the
* path prefix of the selector expression;
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @since 6.0
*/
CompletableFuture subscribeByFilter(
String filter,
TopicSelector topics);
/**
* Subscribe sessions that satisfy a given session filter to topics.
*
*
* This is equivalent to calling
* {@link #subscribeByFilter(String, TopicSelector, SubscriptionByFilterCallback)}
* with a selector parsed using {@link TopicSelectors#parse(String)}.
*
* @param filter the session filter expression
*
* @param topics the topics to subscribe to specified as a
* {@link TopicSelector} expression
*
* @param callback provides callback methods to indicate success or failure
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @since 5.6
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void subscribeByFilter(
String filter,
String topics,
SubscriptionByFilterCallback callback)
throws IllegalArgumentException;
/**
* Subscribe sessions that satisfy a given session filter to topics.
*
*
* For each session that matches the filter, new subscriptions will be
* established for existing topics that match the provided topic selector
* and for which the sessions has {@code READ_TOPIC} permission. The topic
* selector will be added to the topic selections of the subscribed session,
* and re-evaluated when new topics are added or the session's security
* roles change.
*
*
* A session that does not have {@code SELECT_TOPIC} permission for a topic
* cannot subscribe directly, but can be subscribed indirectly using this
* method.
*
* @param filter the session filter expression
*
* @param topics identifies the topics to subscribe to
*
* @param callback provides callback methods to indicate success or failure
*
* @since 5.6
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void subscribeByFilter(
String filter,
TopicSelector topics,
SubscriptionByFilterCallback callback);
/**
* Subscribe sessions that satisfy a given session filter to topics.
*
*
* This is equivalent to calling
* {@link #subscribeByFilter(String, TopicSelector, Object, SubscriptionByFilterContextCallback)}
* with a selector parsed using {@link TopicSelectors#parse(String)}.
*
* @param filter the session filter expression
*
* @param topics the topics to subscribe to specified as a
* {@link TopicSelector} expression
*
* @param context passed to the callback with the reply to allow requests
* and replies to be correlated. The caller may use any convenient
* object reference, including {@code null}
*
* @param callback provides callback methods to indicate success or failure
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @param context object type
*
* @since 5.6
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void subscribeByFilter(
String filter,
String topics,
C context,
SubscriptionByFilterContextCallback callback)
throws IllegalArgumentException;
/**
* Subscribe sessions that satisfy a given session filter to topics.
*
*
* For each session that matches the filter, new subscriptions will be
* established for existing topics that match the provided topic selector
* and for which the sessions has {@code READ_TOPIC} permission. The topic
* selector will be added to the topic selections of the subscribed session,
* and re-evaluated when new topics are added or the session's security
* roles change.
*
*
* A session that does not have {@code SELECT_TOPIC} permission for a topic
* cannot subscribe directly, but can be subscribed indirectly using this
* method.
*
* @param filter the session filter expression
*
* @param topics identifies the topics to subscribe to
*
* @param context passed to the callback with the reply to allow requests
* and replies to be correlated. The caller may use any convenient
* object reference, including {@code null}
*
* @param callback provides callback methods to indicate success or failure
*
* @param context object type
*
* @since 5.6
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void subscribeByFilter(
String filter,
TopicSelector topics,
C context,
SubscriptionByFilterContextCallback callback);
/**
* Unsubscribe sessions that satisfy a given session filter from topics.
*
*
* This is equivalent to calling
* {@link #unsubscribeByFilter(String, TopicSelector)} with a selector
* parsed using {@link TopicSelectors#parse(String)}.
*
* @param filter the session filter expression
*
* @param topics the topics to unsubscribe from specified as a
* {@link TopicSelector} expression
*
* @return a CompletableFuture that completes when the server has processed
* the unsubscription request.
*
*
* If the unsubscription was accepted, the CompletableFuture will
* complete successfully with a {@link SubscriptionByFilterResult}.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link InvalidFilterException} – if the filter is
* invalid;
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code MODIFY_SESSION} and
* {@code VIEW_SESSION} permissions;
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @since 6.0
*/
CompletableFuture unsubscribeByFilter(
String filter,
String topics)
throws IllegalArgumentException;
/**
* Unsubscribe sessions that satisfy a given session filter from topics.
*
* @param filter the session filter expression
*
* @param topics the topics to unsubscribe from specified as a
* {@link TopicSelector} expression
*
* @return a CompletableFuture that completes when the server has processed
* the unsubscription request.
*
*
* If the unsubscription was accepted, the CompletableFuture will
* complete successfully with a {@link SubscriptionByFilterResult}.
*
*
* Otherwise, the CompletableFuture will complete exceptionally with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link InvalidFilterException} – if the filter is
* invalid;
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code MODIFY_SESSION} and
* {@code VIEW_SESSION} global permissions;
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @since 6.0
*/
CompletableFuture unsubscribeByFilter(
String filter,
TopicSelector topics);
/**
* Unsubscribe sessions that satisfy a given session filter from topics.
*
*
* This is equivalent to calling
* {@link #unsubscribeByFilter(String, TopicSelector, SubscriptionByFilterCallback)}
* with a selector parsed using {@link TopicSelectors#parse(String)}.
*
* @param filter the session filter expression
*
* @param topics the topics to unsubscribe specified as a
* {@link TopicSelector} expression
*
* @param callback provides callback methods indicating the status of this
* operation
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @since 5.6
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void unsubscribeByFilter(
String filter,
String topics,
SubscriptionByFilterCallback callback)
throws IllegalArgumentException;
/**
* Unsubscribe sessions that satisfy a given session filter from topics.
*
* @param filter the session filter expression
*
* @param topics the topics to unsubscribe from
*
* @param callback provides callback methods indicating the status of this
* operation
*
* @since 5.6
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void unsubscribeByFilter(
String filter,
TopicSelector topics,
SubscriptionByFilterCallback callback);
/**
* Unsubscribe sessions that satisfy a given session filter from topics.
*
*
* This is equivalent to calling
* {@link #unsubscribeByFilter(String, TopicSelector, SubscriptionByFilterCallback)}
* with a selector parsed using {@link TopicSelectors#parse(String)}.
*
* @param filter the session filter expression
*
* @param topics the topics to unsubscribe specified as a
* {@link TopicSelector} expression
*
* @param context passed to the callback with the reply to allow requests
* and replies to be correlated. The caller may use any convenient
* object reference, including {@code null}
*
* @param callback provides callback methods indicating the status of this
* operation
*
* @throws IllegalArgumentException if {@code topics} is not a valid
* selector expression
*
* @param context object type
*
* @since 5.6
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void unsubscribeByFilter(
String filter,
String topics,
C context,
SubscriptionByFilterContextCallback callback)
throws IllegalArgumentException;
/**
* Unsubscribe sessions that satisfy a given session filter from topics.
*
* @param filter the session filter expression
*
* @param topics the topics to unsubscribe from
*
* @param context passed to the callback with the reply to allow requests
* and replies to be correlated. The caller may use any convenient
* object reference, including {@code null}
*
* @param callback provides callback methods indicating the status of this
* operation
*
* @param context object type
*
* @since 5.6
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
void unsubscribeByFilter(
String filter,
TopicSelector topics,
C context,
SubscriptionByFilterContextCallback callback);
/**
* Callback interface for filtered subscriptions and unsubscriptions.
*
* @since 5.6
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
interface SubscriptionByFilterCallback extends Callback {
/**
* Called to indicate successful processing of the request at the
* server.
*
* @param numberSelected the number of sessions that satisfied the
* filter and qualified for subscription/unsubscription. This
* will be 0 if no sessions satisfied the filter.
*/
void onComplete(int numberSelected);
/**
* The filter was rejected. No sessions were subscribed/unsubscribed.
*
* @param errors the detail of why the filter was rejected
*/
void onRejected(Collection errors);
/**
* Default implementation of {@link SubscriptionByFilterCallback}.
*
* This logs onComplete calls at 'debug' level and onRejected calls at
* 'error' level. This method may be overridden to perform more specific
* processing.
*/
class Default extends
Callback.Default
implements SubscriptionByFilterCallback {
private static final Logger LOG =
LoggerFactory
.getLogger(SubscriptionByFilterCallback.Default.class);
@Override
public void onComplete(int numberSelected) {
LOG.debug(
"{} - Subscription/Unsubscription complete : {} sessions selected",
this,
numberSelected);
}
@Override
public void onRejected(Collection errors) {
LOG.error(
"{} - Subscription/Unsubscription rejected : {}",
this,
errors);
}
}
}
/**
* Callback interface for filtered subscriptions and unsubscriptions that
* have an associated context.
*
* @since 5.6
* @param the context object type
*
* @deprecated since 6.7
*
* Methods that use callbacks are deprecated and will be removed
* in a future release. Use CompletableFuture variant instead.
*/
@Deprecated
interface SubscriptionByFilterContextCallback extends ContextCallback {
/**
* Called to indicate successful processing of the request at the
* server.
*
* @param context the context object the application supplied when
* making the call; may be {@code null}
*
* @param numberSelected the number of sessions that satisfied the
* filter and qualified for subscription/unsubscription. This
* will be 0 if no sessions satisfied the filter.
*/
void onComplete(C context, int numberSelected);
/**
* The filter was rejected. No sessions were subscribed/unsubscribed.
*
* @param context the context object supplied when making the call
*
* @param errors the detail of why the filter was rejected
*/
void onRejected(C context, Collection errors);
/**
* Default implementation of {@link SubscriptionByFilterContextCallback}
* .
*
* This logs onComplete calls at 'debug' level and onRejected calls at
* 'error' level. This method may be overridden to perform more specific
* processing.
*
* @param context object type
*/
class Default
extends
ContextCallback.Default
implements SubscriptionByFilterContextCallback {
private static final Logger LOG =
getLogger(SubscriptionByFilterContextCallback.Default.class);
@Override
public void onComplete(C context, int numberSelected) {
LOG.debug(
"{} - Subscription/Unsubscription complete : {} sessions selected, Context={}",
this,
numberSelected,
context);
}
@Override
public void onRejected(C context, Collection errors) {
LOG.error(
"{} - Subscription/Unsubscription rejected : {}, Context={}",
this,
errors,
context);
}
}
}
/**
* A single request from a session to subscribe to routing topic.
*
*
* Each request received by a handler must either be {@link #route routed}
* or {@link #defer deferred}.
*
* @deprecated since 6.7
*
* Routing topics are deprecated. The more powerful
* {@link SessionTrees} feature should be used in their place.
*/
@Deprecated
interface RoutingSubscriptionRequest {
/**
* Identifies the session making the subscription request.
*
* @return the session id of the requesting session
*/
SessionId getSessionId();
/**
* Identifies the subscribed routing topic.
*
* @return the topic path of the routing topic
*/
String getTopicPath();
/**
* Defer the handling of this subscription request.
*
*
* When a request is deferred, the server will discard the request, and
* the requesting session will not receive a subscription notification.
*
*
* An implementation can retain the requesting session's
* {@link #getSessionId() session ID} and the routing topic's
* {@link #getTopicPath() path} so a routing subscription can be
* established at a later time using
* {@link SubscriptionControl#subscribe(SessionId, String, SubscriptionCallback)}.
*
*
* A {@code RoutingSubscriptionRequest} can be used once. If
* {@code route()} or {@code defer()} has already been called for this
* {@code RoutingSubscriptionRequest}, calling this method will cause a
* warning to be logged by the server, but otherwise have no effect.
*
*
Behavior since 6.0
*
*
* From 6.0, this method returns a CompletableFuture and no longer
* throws exceptions. All errors are reported through the
* CompletableFuture result.
*
* @return a CompletableFuture that completes when the server has
* processed the defer instruction.
*
*
* If the instruction was processed, the CompletableFuture will
* complete successfully. The result type is any rather than
* Void to provide forward compatibility with future iterations
* of this API that may provide a non-null result with a more
* specific result type.
*
*
* Otherwise, the CompletableFuture will complete exceptionally
* with a {@link CompletionException}. Common reasons for
* failure, listed by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link SessionException} – if {@code route()} or
* {@code defer()} has already been called for this
* {@code RoutingSubscriptionRequest};
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*/
CompletableFuture> defer();
/**
* Resolve a subscription request by providing the path of a source
* topic to which the requesting session will be subscribed via the
* routing topic.
*
*
* The requesting session will receive a subscription notification with
* the routing topic's path and the topic specification of the source
* topic. If the source topic is stateful, the requesting session will
* also be sent an update for the routing topic path with the current
* value of the source topic. The existence of the source topic is
* hidden from the requesting session. Updates to the source topic are
* forwarded to the session as if they came from the routing topic.
*
*
* A session that does not have {@code SELECT_TOPIC} or
* {@code READ_TOPIC} permission for the source topic cannot subscribe
* directly, but can be subscribed indirectly using this method.
*
* @param topicPath the topic path of the source topic
* @return a CompletableFuture that completes when the server has
* processed the routing instruction.
*
*
* If a routing subscription was established, the
* CompletableFuture will complete successfully. The result type
* is any rather than Void to provide forward compatibility
* with future iterations of this API that may provide a
* non-null result with a more specific result type.
*
*
* Otherwise, the CompletableFuture will complete exceptionally
* with a {@link CompletionException}. Common reasons for
* failure, listed by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
*
* - {@link RoutingSubscriptionException} – if there is
* no topic bound to {@code topicPath};
*
*
- {@link RoutingSubscriptionException} – if the topic
* bound to {@code topicPath} is itself a routing topic;
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code READ_TOPIC} permission for the
* source topic bound to {@code topicPath};
*
*
- {@link PermissionsException} – if the calling
* session does not have {@code READ_TOPIC} permission for the
* routing topic bound to {@link #getTopicPath()};
*
*
- {@link SessionException} – if {@code route()} or
* {@code defer()} has already been called for this
* {@code RoutingSubscriptionRequest};
*
*
- {@link SessionClosedException} – if the session is
* closed.
*
*/
CompletableFuture> route(String topicPath);
/**
* Resolve a subscription request by providing the path of a source
* topic to which the requesting session will be subscribed via the
* routing topic.
*
*
* The requesting session will receive a subscription notification with
* the routing topic's path and the topic specification of the source
* topic. If the source topic is stateful, the requesting session will
* also be sent an update for the routing topic path with the current
* value of the source topic. The existence of the source topic is
* hidden from the requesting session. Updates to the source topic are
* forwarded to the session as if they came from the routing topic.
*
*
* A session that does not have {@code SELECT_TOPIC} or
* {@code READ_TOPIC} permission for the source topic cannot subscribe
* directly, but can be subscribed indirectly using this method.
*
*
* The operation will fail and the callback with be
* {@link SubscriptionCallback#onDiscard() discarded} in the following
* cases:
*
*
* - There is no source topic bound to {@code topicPath};
*
- The topic bound to {@code topicPath} is a routing topic;
*
- The calling session does not have {@code READ_TOPIC} permission
* for the source topic bound to {@code topicPath};
*
- The calling session does not have {@code READ_TOPIC} permission
* for the routing topic bound to {@link #getTopicPath()};
*
- {@code route()} or {@code defer()} has already been called for
* this {@code RoutingSubscriptionRequest}.
*
*
* @param topicPath the topic path of the resolved source topic
*
* @param callback provides callback methods indicating the status of
* this request.
*/
void route(String topicPath, SubscriptionCallback callback);
/**
* Provide the path of a source topic to which the requesting session
* will be subscribed via the routing topic, with a contextual object.
*
*
* The requesting session will receive a subscription notification with
* the routing topic's path and the topic specification of the source
* topic. If the source topic is stateful, the requesting session will
* also be sent an update for the routing topic path with the current
* value of the source topic. The existence of the source topic is
* hidden from the requesting session. Updates to the source topic are
* forwarded to the session as if they came from the routing topic.
*
*
* A session that does not have {@code SELECT_TOPIC} or
* {@code READ_TOPIC} permission for the source topic cannot subscribe
* directly, but can be subscribed indirectly using this method.
*
*
* The operation will fail and the callback with be
* {@link SubscriptionCallback#onDiscard() discarded} in the following
* cases:
*
*
* - There is no source topic bound to {@code topicPath};
*
- The topic bound to {@code topicPath} is a routing topic;
*
- The calling session does not have {@code READ_TOPIC} permission
* for the source topic bound to {@code topicPath};
*
- The calling session does not have {@code READ_TOPIC} permission
* for the routing topic bound to {@link #getTopicPath()};
*
- {@code route()} or {@code defer()} has already been called for
* this {@code RoutingSubscriptionRequest}.
*
*
* @param topicPath the topic path of the resolved source topic
*
* @param context passed to the callback with the reply to allow
* requests and replies to be correlated. The caller may use any
* convenient object reference, including {@code null}
*
* @param callback provides callback methods indicating the status of
* this request.
*
* @param context object type
*/
void route(
String topicPath,
C context,
SubscriptionContextCallback callback);
/**
* Handler for routing subscription requests.
*
* @deprecated since 6.7
*
* Routing topics are deprecated. The more powerful
* {@link SessionTrees} feature should be used in their
* place.
*/
@Deprecated
interface RoutingHandler extends Stream {
/**
* A request to subscribe to a specific routing topic.
*
* @param request the request, which must be replied to or deferred
*/
void onSubscriptionRequest(RoutingSubscriptionRequest request);
/**
* Abstract handler implementation.
*
* The
* {@link RoutingHandler#onSubscriptionRequest(SubscriptionControl.RoutingSubscriptionRequest)
* onSubscriptionRequest} method must be implemented.
*/
abstract class Default
extends Stream.Default implements RoutingHandler {
}
}
/**
* Handler for routing subscription requests registered with the older,
* callback-based
* {@link SubscriptionControl#addRoutingSubscriptionHandler(String, SubscriptionControl.RoutingSubscriptionRequest.Handler)
* addRoutingSubscriptionHandler(String, Handler)} method.
*
* @deprecated since 6.7
*
* Routing topics are deprecated. The more powerful
* {@link SessionTrees} feature should be used in their
* place.
*/
@Deprecated
interface Handler extends TopicTreeHandler {
/**
* A request to subscribe to a specific routing topic.
*
* @param request the request, which must be replied to or deferred
*/
void onSubscriptionRequest(RoutingSubscriptionRequest request);
/**
* Abstract handler implementation.
*
* The
* {@link Handler#onSubscriptionRequest(SubscriptionControl.RoutingSubscriptionRequest)
* onSubscriptionRequest} method must be implemented.
*/
abstract class Default
extends TopicTreeHandler.Default implements Handler {
}
}
}
/**
* Result used by CompletableFuture variants of
* {@link SubscriptionControl#subscribeByFilter(String, String)
* subscribeByFilter} and
* {@link SubscriptionControl#unsubscribeByFilter(String, String)
* unsubscribeByFilter}.
*
* @since 6.0
*/
public interface SubscriptionByFilterResult {
/**
* @return number of sessions that satisfied the filter and qualified
* for subscription/unsubscription. This will be 0 if no
* sessions satisfied the filter.
*/
int numberSelected();
}
}