com.pushtechnology.diffusion.client.features.UpdateStream Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2018, 2023 DiffusionData Ltd., All Rights Reserved.
*
* Use is subject to licence terms.
*
* NOTICE: All information contained herein is, and remains the
* property of DiffusionData. The intellectual and technical
* concepts contained herein are proprietary to DiffusionData 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;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import com.pushtechnology.diffusion.client.Diffusion;
import com.pushtechnology.diffusion.client.features.control.topics.TopicControl.IncompatibleExistingTopicException;
import com.pushtechnology.diffusion.client.features.control.topics.TopicControl.InvalidTopicPathException;
import com.pushtechnology.diffusion.client.features.control.topics.TopicControl.InvalidTopicSpecificationException;
import com.pushtechnology.diffusion.client.features.control.topics.TopicControl.TopicLicenseLimitException;
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.retry.RetryStrategy;
import com.pushtechnology.diffusion.client.topics.details.TopicSpecification;
import com.pushtechnology.diffusion.client.topics.details.TopicType;
/**
* An update stream provides a method for updating a specific topic.
*
*
* An update stream is associated with a specific topic.
* Update streams are created using {@link TopicUpdate#newUpdateStreamBuilder()}.
* It can be created with an optional {@link UpdateConstraint constraint}. An
* optional {@link TopicSpecification} can be provided on creation.
* The type of the topic must match the type of values passed to the update stream.
* The existence of the topic, its type and the constraint are validated lazily
* by the first {@link UpdateStream#set} or {@link UpdateStream#validate}
* operation. Subsequent operations issued before the first operation
* completes will be deferred until the completion of the first operation.
*
* An update stream can be used to send any number of updates. It sends a
* sequence of updates for a specific topic to the server. If supported by the
* data type, updates will be sent to the server as a stream of binary deltas.
* An update stream does not prevent other sessions from updating the topic. If
* exclusive access is required update streams should be used with
* {@link com.pushtechnology.diffusion.client.session.Session.SessionLock session locks}
* as constraints.
*
* Once validated an update stream can be invalidated. An invalidated
* update stream rejects the operations applied to it. The update stream
* will be invalidated if:
*
* - the topic is removed
*
- another update stream is created for the same topic
*
- the topic is updated to a new value by anything other than the stream
*
- the session does not have the
* {@link com.pushtechnology.diffusion.client.types.PathPermission#UPDATE_TOPIC
* UPDATE_TOPIC} permission
*
- an operation fails because of cluster repartitioning
*
*
* Update streams are thread-safe.
*
* @param type of the value
* @author DiffusionData Limited
* @since 6.2
*/
public interface UpdateStream {
/**
* Sets the topic to a specified value.
*
* The {@code null} value can only be passed to the {@code value}
* parameter when updating {@link TopicType#STRING string},
* {@link TopicType#INT64 int64}, or {@link TopicType#DOUBLE double} topics.
*
* When a {@link TopicType#STRING string}, {@link TopicType#INT64 int64}, or
* {@link TopicType#DOUBLE double} topic is set to {@code null}, the topic
* will be updated to have no value. If a previous value was present
* subscribers will receive a notification that the new value is
* {@code null}. New subscribers will not receive a value notification.
*
* The first call to this method may fail with
* {@link NoSuchTopicException} or {@link IncompatibleTopicException}.
* Subsequent calls may fail with {@link InvalidUpdateStreamException}.
* Any call can fail with {@link ClusterRoutingException},
* {@link PermissionsException} or {@link SessionClosedException}.
*
* If a {@link UpdateConstraint constraint} was provided when creating the
* update stream, the first call to this method may also fail with
* {@link UnsatisfiedConstraintException}.
*
* If the update stream was created with a {@link TopicSpecification},
* the first call to this method may also fail with
* {@link IncompatibleExistingTopicException} and it will not fail with
* {@link NoSuchTopicException}.
*
* If this method fails all subsequent calls to {@link #set} or
* {@link #validate} will fail with {@link InvalidUpdateStreamException}.
*
* @param value the value. Update streams for
* {@link TopicType#STRING string},
* {@link TopicType#INT64 int64}, and
* {@link TopicType#DOUBLE double}
* topics accept {@code null}, as described above. Using
* null with other topic types is an error and will result
* in a {@link NullPointerException}.
* @return a CompletableFuture that completes when a response is received
* from the server.
*
*
* If the task fails, 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 NoSuchTopicException} – if there is no topic
* bound to {@code path};
*
- {@link IncompatibleTopicException} – if updates
* cannot be applied to the topic, for example if a topic view has
* bound a reference topic to the path;
*
- {@link IncompatibleTopicStateException} – if the topic
* is managed by a component (such as fan-out) that prohibits
* updates from the caller;
*
- {@link UnsatisfiedConstraintException} – if the
* {@code constraint} is not satisfied by the topic {@code path};
*
- {@link InvalidUpdateStreamException} – the update
* stream has been invalidated;
*
- {@link InvalidTopicPathException} – {@code topicPath}
* is not a valid topic path;
*
- {@link InvalidTopicSpecificationException} – the
* specification is invalid, possibly because mandatory properties
* not supplied;
*
- {@link TopicLicenseLimitException} – the
* topic could not be added as it would breach a licensing limit;
*
- {@link ClusterRoutingException} – if the operation failed
* due to a transient cluster error;
*
- {@link PermissionsException} – if the calling
* session does not have the {@code MODIFY_TOPIC} or
* {@code UPDATE_TOPIC} permission for {@code path};
*
- {@link SessionClosedException} – if the session is
* closed.
*
*/
CompletableFuture set(T value);
/**
* Return the latest value of the topic set using this update stream.
*
* The returned value reflects the last value that has been set, before it
* is sent to the server.
*
* If the server rejects a set operation, the topic value will not change
* and this update stream will be invalidated.
*
* @return the cached value of the topic
* @throws IllegalStateException if called before the first call to
* {@link #set}
*/
T get();
/**
* Validates the update stream.
*
* Update streams are validated lazily when
* {@link #set setting the value}. This method allows the stream to be
* validated before a value needs to be set.
*
* If the update stream has not been validated yet, calling this method
* checks the topic exists, the topic type is correct, the constraint is
* satisfied and the session has permission to update the topic. Once
* it has been validated calling this method checks the topic has not been
* removed, no other stream has been created for the topic, the value
* of the topic has not been changed by anything else and the session
* still has permission to update the topic.
*
* This method may fail with {@link IncompatibleExistingTopicException}
* if it is the first call to {@link #validate}, {@link #set} has not
* been called and a {@link TopicSpecification topic specification} was
* provided when creating the update stream, otherwise it will never
* fail with this cause.
*
* The first call to this method may fail with
* {@link NoSuchTopicException} or {@link IncompatibleTopicException}.
* Subsequent calls may fail with {@link InvalidUpdateStreamException}.
* Any call can fail with {@link ClusterRoutingException},
* {@link PermissionsException} or {@link SessionClosedException}.
*
* If a {@link UpdateConstraint constraint} was provided when creating the
* update stream, the first call to this method may also fail with
* {@link UnsatisfiedConstraintException}.
*
* If the update stream was created with a {@link TopicSpecification},
* the first call to this method may also fail with
* {@link IncompatibleExistingTopicException} and it will not fail with
* {@link NoSuchTopicException}.
*
* If this method fails all subsequent calls to {@link #set} or
* {@link #validate} will fail with {@link InvalidUpdateStreamException}.
*
* @return a CompletableFuture that completes when a response is received
* from the server.
*
*
* If the task fails, 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 NoSuchTopicException} – if there is no topic
* bound to {@code path};
*
- {@link IncompatibleTopicException} – if updates
* cannot be applied to the topic, for example if a topic view has
* bound a reference topic to the path;
*
- {@link IncompatibleTopicStateException} – if the topic
* is managed by a component (such as fan-out) that prohibits
* updates from the caller;
*
- {@link UnsatisfiedConstraintException} – if the
* {@code constraint} is not satisfied by the topic {@code path};
*
- {@link InvalidUpdateStreamException} – the update
* stream has been invalidated;
*
- {@link ClusterRoutingException} – if the operation failed
* due to a transient cluster error;
*
- {@link PermissionsException} – if the calling
* session does not have the {@code MODIFY_TOPIC} or
* {@code UPDATE_TOPIC} permission for {@code path};
*
- {@link SessionClosedException} – if the session is
* closed.
*
*/
CompletableFuture validate();
/**
* Builder for {@link UpdateStream update stream} to use for updating a
* specific topic. A builder is created using
* {@link TopicUpdate#newUpdateStreamBuilder}.
*
* The type of the topic being updated must match the type derived from the
* {@code valueClass} parameter.
*
* @since 6.9
*/
interface Builder {
/**
* Specifies a TopicSpecification for this update stream.
*
* If a topic does not exist at the {@code path} one will be created using
* the {@code topicSpecification} when the update stream is validated. If a
* topic does exist, its specification must match {@code topicSpecification},
* otherwise the operation will fail with
* {@link IncompatibleTopicException}.
*
* Specification is null by default. Calling this method with a null parameter
* removes the specification for this builder.
*
* @param topicSpecification the required specification of the topic
* @return this builder
*/
Builder specification(TopicSpecification topicSpecification);
/**
* Specifies an update constraint for this update stream.
*
* Constraints can be created using {@link Diffusion#updateConstraints}}.
*
* Constraints can be applied to the setting of a value and creation of an
* update stream. Constraints describe a condition that must be satisfied for
* the operation to succeed. The constraints are evaluated on the server. The
* available constraints are: an active session lock, the absence of a topic,
* the current value of the topic being updated, and a part of the current
* value of the topic being updated.
*
* Constraint is Unconstrained by default. Calling this method with a null parameter
* resets the constraint for this builder.
*
* @param updateConstraint the constraint that must be satisfied for the update
* stream to be validated
* @return this builder
*/
Builder constraint(UpdateConstraint updateConstraint);
/**
* Resets the builder to its default parameters.
*
* @return this builder
*/
Builder reset();
/**
* Creates an {@link UpdateStream} to use for updating a
* specific topic.
*
* The type of the topic being updated must match the type derived from the
* {@code valueClass} parameter.
*
* Update streams send a sequence of updates for a specific topic. The
* updates may be delivered to the server as binary deltas. They do not
* provide exclusive access to the topic. If exclusive access is required
* update streams should be used with
* {@link Session.SessionLock session locks} as constraints.
*
* Streams are validated lazily when the first {@link UpdateStream#set} or
* {@link UpdateStream#validate} operation is completed. Once validated a
* stream can be invalidated, after which it rejects future
* updates.
*
* @param path the path of the topic
* @param valueClass the type of the values expected by the update stream
* @param type of the values expected by the update stream
*
* @return an update stream
*/
UpdateStream build(String path, Class valueClass);
/**
* Creates a {@link RecoverableUpdateStream} to use for updating a
* specific topic.
*
* Takes a retry strategy that governs recovery attempts following a
* recoverable exception.
*
* In other respects this method works in the same way as
* {@link #build(String, Class)}.
*
* @param path the path of the topic
* @param valueClass the type of the values expected by the update stream
* @param type of the values expected by the update stream
*
* @return a recoverable update stream
*
* @since 6.10
*/
RecoverableUpdateStream build(
String path,
Class valueClass,
RetryStrategy strategy);
}
}