com.pushtechnology.diffusion.client.topics.TopicSelectors 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.topics;
import java.util.regex.Pattern;
/**
* Convert strings to {@link TopicSelector}s.
*
*
* Selectors are evaluated against topic paths. A topic path is a '/' separated
* string of parts, which map to the topic tree. Each part is formed of one
* or more UTF characters, except '/'. Topic paths are absolute, and evaluated
* from the root of the topic tree.
*
* An instance of this may be obtained as follows:
*
*
* TopicSelectors selectors = Diffusion.topicSelectors();
*
*
*
*
* @author DiffusionData Limited
* @since 5.0
*/
public interface TopicSelectors {
/**
* Parse an expression to create a selector.
*
*
* The following types of expression are supported. The type is determined
* by the first character of the expression.
*
*
*
* - Path
*
- Path expressions begin with the character {@code >}. The remainder of
* the expression must be a valid topic path. A topic path is a '/'
* separated string of parts. Each part is formed of one or more UTF
* characters, except '/'.
*
* A {@link TopicSelector.Type#PATH PATH} selector is returned that only
* selects the topic with the given path.
*
*
* The initial {@code >} can be omitted if the path begins with a character
* other than one of {@code #}, {@code ?}, {@code >}, {@code *}, {@code $},
* {@code %}, {@code &}, or {@code <}. This abbreviated syntax allows most
* topic paths to be used directly as selector expressions which appears
* more natural. Abbreviated path expressions are converted to standard path
* expressions by prepending the {@code >} character. Thus {@code a/b} is
* interpreted as {@code >a/b}.
*
* {@code Diffusion.topicSelectors().parse("a/b").getExpression()} will
* return {@code ">a/b"}.
*
*
- Split-path pattern
*
- Split-path pattern expressions begin with the character {@code ?}.
* The remainder of the expression is split into a list of regular
* expressions using the {@code /} character as a separator.
*
*
* A {@link TopicSelector.Type#SPLIT_PATH_PATTERN SPLIT_PATH_PATTERN}
* selector is returned that selects topics for which each regular
* expression matches each part of the topic path at the corresponding
* level.
*
*
* - Full-path pattern
*
- Full-path pattern expressions begin with the character {@code *}. The
* remainder of the pattern is a regular expression.
*
*
* A {@link TopicSelector.Type#FULL_PATH_PATTERN FULL_PATH_PATTERN} selector
* is returned that selects topics for which the regular expression matches
* the complete topic path.
*
*
*
* Full-path patterns provide a lot of expressive power but should be used
* sparingly since the server can evaluate split-path patterns more
* efficiently.
*
*
* Selector sets are the preferred way to combine expressions.
* {@code anyOf("a", "b")} is equivalent to the full-path expression "
* {@code *}{@code /a|/b}", but can be evaluated more efficiently by the
* server.
*
*
- Selector set
*
- Selector set expressions begin with the character {@code #}. The
* remainder of the expression is a list of contained selectors, formatted
* as described below.
*
*
* A {@link TopicSelector.Type#SELECTOR_SET SELECTOR_SET} selector is
* returned that selects topics that match any of the contained selectors.
*
*
*
* The selector set expression format is complex, The
* {@link #anyOf(String...)} convenience method should be preferred over
* calling this method with a selector set expression. The contained
* selectors are formatted as follows. First, any selector sets are expanded
* to produce a full list of non-selector set expressions. Then the selector
* expressions are concatenated, separated by the separator {@code ////}.
* This separator has been chosen as it is not valid in a path, and is not a
* useful sequence in a pattern.
*
*
*
*
* Descendant pattern qualifiers
*
*
* Split-path and full-path pattern expressions can be further modified by
* appending {@code /} or {@code //}. These control the behavior of the
* selector with respect to the descendants of the topics that match the
* pattern.
*
*
*
* - If the expression does not end with {@code /} or {@code //}, it
* selects only the topics that match the pattern.
*
* - If the expression ends with {@code /}, it selects only the
* descendants of the matching topics, excluding the matching topics.
*
* - If the expression ends with {@code //}, it selects the matching
* topics and all of their descendants.
*
*
* Regular expressions
*
*
* Any {@link Pattern Java-style regular expression} can be used in
* split-path and full-path patterns, with the following restrictions:
*
*
* - A regular expression may not be empty.
*
- A regular expression used in split-path patterns may not contain the
* path separator {@code /}.
*
- A regular expression used in full-path patterns may not contain the
* selector set separator {@code ////} .
*
*
*
* Regular expressions that break any of these restrictions would never
* match a topic path, so they make no practical difference.
*
*
*
* Examples
*
* Path expressions
*
*
*
* Matches {@code alpha/beta}?
* Matches {@code alpha/beta/gamma}?
*
*
*
* {@code >alpha/beta}
* yes
* no
*
*
*
* {@code alpha/beta}
* yes
* no
*
*
*
* {@code >alpha/beta/gamma}
* no
* yes
*
*
*
* {@code alpha/beta/gamma}
* no
* yes
*
*
*
* {@code >beta}
* no
* no
*
*
*
* {@code beta}
* no
* no
*
*
*
* {@code >.*}{@code /.*}
* no
* no
*
*
*
* {@code >/alpha/beta/}
* yes
* no
*
*
*
* {@code /alpha/beta/}
* yes
* no
*
*
*
*
* Split-path pattern expressions
*
*
*
* Matches {@code alpha/beta}?
* Matches {@code alpha/beta/gamma}?
*
*
*
* {@code ?alpha/beta}
* yes
* no
*
*
*
* {@code ?alpha/beta/gamma}
* no
* yes
*
*
*
* {@code ?beta}
* no
* no
*
*
*
* {@code ?.*}
* no
* no
*
*
*
* {@code ?.*}{@code /.*}
* yes
* no
*
*
*
* {@code ?alpha/beta/}
* no
* yes
*
*
*
* {@code ?alpha/beta//}
* yes
* yes
*
*
*
* {@code ?alpha/.*}{@code //}
* yes
* yes
*
*
*
*
* Full-path pattern expressions
*
*
*
* Matches {@code alpha/beta}?
* Matches {@code alpha/beta/gamma}?
*
*
*
* {@code *alpha/beta}
* yes
* no
*
*
*
* {@code *alpha/beta/gamma}
* no
* yes
*
*
*
* {@code *beta}
* no
* no
*
*
*
* {@code *.*beta}
* yes
* no
*
*
*
* {@code *.*}
* yes
* yes
*
*
*
*
* {@code *alpha/beta/}
* no
* yes
*
*
*
* {@code *alpha/beta//}
* yes
* yes
*
*
*
* @param expression The topic selector expression.
* @return The topic selector.
* @throws IllegalArgumentException If {@code expression} is not valid.
* @throws IllegalArgumentException If {@code expression} is not one of the
* supported types.
*/
TopicSelector parse(String expression) throws IllegalArgumentException;
/**
* Convenient wrapper of {@link #anyOf(TopicSelector...)} that first parses
* the supplied expressions to create selectors.
*
* @param expressions The expressions.
* @return A selector which matches any of {@code expressions}.
* @throws IllegalArgumentException If one of {@code expressions} cannot be
* {@link #parse parsed}.
*/
TopicSelector anyOf(String... expressions) throws IllegalArgumentException;
/**
* Create a {@code SELECTOR_SET} selector that matches if any of the
* provided {@code selectors} match.
*
* @param selectors The selectors.
* @return A selector which matches if any of {@code selectors} do.
*/
TopicSelector anyOf(TopicSelector... selectors);
}