com.pushtechnology.diffusion.client.features.control.topics.SessionTrees Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2021, 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.control.topics;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import com.pushtechnology.diffusion.client.Diffusion;
import com.pushtechnology.diffusion.client.features.ClusterRoutingException;
import com.pushtechnology.diffusion.client.features.Topics;
import com.pushtechnology.diffusion.client.features.control.topics.views.TopicViews;
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.types.PathPermission;
/**
* This feature allows a client session to configure session trees.
*
*
* A session tree is a virtual view of the topic tree presented to a session by
* fetch and subscription operations. Custom session trees for different
* sessions can be configured using declarative rules maintained by the server
* to meet data security, data optimisation, or personalisation and localisation
* requirements. Each session can be presented with a unique session tree based
* on its session properties.
*
*
* A session tree is produced by applying branch mappings to the topic
* tree. Branch mappings are organised into branch mapping tables. Each
* branch mapping table is assigned to a unique path – the session tree
* branch.
*
*
* A session tree is composed of session paths. Each session path is
* mapped via the branch mapping tables to a unique topic path.
*
*
* A branch mapping table is an ordered list of (session filter, topic tree
* branch) pairs. For example, the branch mapping table for the session tree
* branch {@code market/prices} might be:
*
*
* Session filter Topic tree branch
* ============== =================
* USER_TIER is '1' or $Country is 'DE' backend/discounted_prices
* USER_TIER is '2' backend/standard_prices
* $Principal is '' backend/delayed_prices
*
*
*
* With this configuration, if an unauthenticated session (one that matches the
* {@code $Principal is ''} session filter) subscribes to the session path
* {@code market/prices/X}, and there is a topic bound to the topic path
* {@code backend/delayed_prices/X}, the subscription will complete. The session
* will receive a subscription notification under the session path
* {@code market/prices/X}, together with the topic properties and the value of
* the topic. The session is unaware that the data originates from a topic bound
* to a different topic path. If no topic is bound to
* {@code backend/delayed_prices/X}, the subscription will not resolve and the
* session will receive no data, even if there is a topic bound to
* {@code market/prices/X}.
*
*
* Session trees complement the data transformation capabilities of
* {@link TopicViews topic views}. In our example, the time delayed time feed at
* {@code backend/delayed_prices} could be maintained by a topic view using the
* delay by clause.
*
*
* Branch mappings are persisted by the server and shared across a cluster, in a
* similar manner to topic views, security stores, and metric collectors. Branch
* mappings are editable using this feature, and via the management console.
*
*
* For a given session and session path, at most one branch mapping applies. The
* applicable branch mapping is chosen as follows:
*
* - Each branch mapping table with session tree branch that is a prefix of
* the session path is considered. For a given table, the first branch mapping
* with a session filter that matches the session's properties is the one that
* applies. A branch mapping table may have no applicable branch mappings for a
* session.
*
- If there are several such branch mapping tables with a branch mapping
* that for the session, the one with the longest prefix of the session path
* applies.
*
- If no branch mapping table has a branch mapping for the session, the
* session path is translated to the identical topic path.
*
*
* Access control
*
* To subscribe to or fetch from a session path, a session must be granted the
* appropriate path permission to the session path for the operation
* ({@link PathPermission#SELECT_TOPIC SELECT_TOPIC}, or
* {@link PathPermission#READ_TOPIC READ_TOPIC}). The session doesn't require
* any permissions to the topic path of the topic providing the data.
*
*
* To create or replace branch mappings, a session needs the
* {@link PathPermission#MODIFY_TOPIC MODIFY_TOPIC} path permission for the
* session tree branch of the branch mapping table,
* {@link PathPermission#EXPOSE_BRANCH EXPOSE_BRANCH} path permission for the
* topic tree branch of each branch mapping, and (if an existing table with the
* same session tree branch is being replaced)
* {@link PathPermission#EXPOSE_BRANCH EXPOSE_BRANCH} permission for each branch
* mapping of existing table.
*
*
* To retrieve a branch mapping table, a session needs the
* {@link PathPermission#READ_TOPIC READ_TOPIC} path permission for its session
* tree branch.
*
*
Accessing the feature
*
* This feature may be obtained from a {@link Session session} as follows:
*
*
* SessionTrees sessionTrees = session.feature(SessionTrees.class);
*
*
*
* This feature is also extended by the {@link Topics Topics} feature. This
* means is it possible to use the methods described here through the
* {@link Topics Topics} feature.
*
* @author DiffusionData Limited
*
* @since 6.7
*/
public interface SessionTrees extends Feature {
/**
* A session tree branch mapping.
*
* Branch mappings belong to {@link BranchMappingTable branch mapping
* tables}. Each branch mapping is a pair of a {@link Session session
* filter} and the target topic tree branch that applies to sessions
* matching the filter.
*/
interface BranchMapping {
/**
* Returns the session filter.
*
* @return the session filter
*/
String getSessionFilter();
/**
* Returns the target branch in the topic tree for sessions matching the
* session filter.
*
* @return the target branch
*/
String getTopicTreeBranch();
}
/**
* A session tree branch mapping table.
*
*
* A branch mapping table is a list of {@link BranchMapping branch mappings}
* assigned to a session tree branch.
*
* To create a branch mapping table, obtain a new a builder instance using
* {@link Diffusion#newBranchMappingTableBuilder()}, call
* {@link Builder#addBranchMapping} for each branch mapping, then
* {@link Builder#create}. The result can then be sent to the server using
* {@link SessionTrees#putBranchMappingTable putBranchMappingTable}.
*/
interface BranchMappingTable {
/**
* Returns the branch of the session tree to which this table is bound.
*
* @return the session tree branch
*/
String getSessionTreeBranch();
/**
* Returns the branch mappings.
*
* @return the branch mappings
*/
List getBranchMappings();
/**
* Builder for {@link BranchMappingTable} instances.
*
* @see Diffusion#newBranchMappingTableBuilder()
*/
interface Builder {
/**
* Reset the builder.
*
* @return this Builder
*/
Builder reset();
/**
* Add a new branch mapping.
*
* @param sessionFilter the session filter
*
* @param topicTreeBranch the target branch in the topic tree for
* sessions matching the session filter
*
* @return this Builder
*/
Builder addBranchMapping(String sessionFilter,
String topicTreeBranch);
/**
* Create a new branch mapping table.
*
* @param sessionTreeBranch the session tree branch
*/
BranchMappingTable create(String sessionTreeBranch);
}
}
/**
* Exception indicating an invalid {@link BranchMapping} or
* {@link BranchMappingTable}.
*/
class InvalidBranchMappingException extends SessionException {
private static final long serialVersionUID = -8177607860793468364L;
/**
* Constructor.
*/
public InvalidBranchMappingException(String message) {
super(message);
}
}
/**
* Create or replace a branch mapping table.
*
*
* The server ensures that there is at most one branch mapping table for a
* session tree branch. Putting a new branch mapping table will replace any
* previous branch mapping table with the same session tree branch. To
* remove all branch mappings for a session tree branch, put an empty branch
* mapping table.
*
* @param branchMappingTable the new table
*
* @return a CompletableFuture that completes when a response is received
* from the server.
*
*
* If the task completes successfully, the CompletableFuture result
* will be null. 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 InvalidBranchMappingException} – if
* branchMappingTable or one of its branch mappings is invalid;
*
- {@link PermissionsException} – if the calling
* session does not have the {@link PathPermission#MODIFY_TOPIC
* MODIFY_TOPIC} permission for the session tree branch of the
* branch mapping table, {@link PathPermission#EXPOSE_BRANCH
* EXPOSE_BRANCH} permission for each branch mapping of
* branchMappingTable, and (if there is an existing table for the
* session tree branch) {@link PathPermission#EXPOSE_BRANCH
* EXPOSE_BRANCH} permission for each branch mapping of existing
* table;
*
- {@link ClusterRoutingException} – if the operation
* failed due to a transient cluster error;
*
- {@link SessionClosedException} – if the session is
* closed.
*
*/
CompletableFuture> putBranchMappingTable(
BranchMappingTable branchMappingTable);
/**
* Retrieve the session tree branches of the server's branch mapping tables.
* The results will only include the session tree branches of branch mapping
* tables that have at least one branch mapping and for which the calling
* session has {@link PathPermission#READ_TOPIC READ_TOPIC} path permission
* for the session tree branch.
*
*
* Individual branch mapping tables can be retrieved using
* {@link #getBranchMappingTable(String)}.
*
* @return a CompletableFuture that completes when a response is received
* from the server, returning a list of session tree branches in
* path order.
*
*
* 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 SessionClosedException} – if the session is
* closed.
*
*/
CompletableFuture> listSessionTreeBranchesWithMappings();
/**
* Retrieve a branch mapping table from the server.
*
*
* If there is no branch mapping table at the given session tree branch,
* this method will return an empty branch mapping table.
*
* @param sessionTreeBranch the session tree branch that identifies the
* branch mapping table
*
* @return a CompletableFuture that completes when a response is received
* from the server, returning the branch mapping table for
* sessionTreeBranch.
*
*
* 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 PermissionsException} – if the calling
* session does not have the {@link PathPermission#READ_TOPIC
* READ_TOPIC} permission for sessionTreeBranch;
*
- {@link SessionClosedException} – if the session is
* closed.
*
*/
CompletableFuture getBranchMappingTable(
String sessionTreeBranch);
}