Class Path
When working with Paths, leading and trailing slashes are completely disregarded. Any leading and trailing slashes in the documentation are illustrative only and could be excluded to achieve the same result. Multiple consecutive slashes are treated as a single slash. There will never be an empty string or null path part.
In addition to representing concrete paths, such as a file path or url path, a Path object may contain wildcards, regular expressions, and variable name bindings which are used when comparing a variablized abstract paths with a concrete path.
Paths are primarily used to configure Rules (Engine, Api, Endpoint and Action are all subclasses of Rule) to match against inbound Request urls to determine how the Request will be processed.
Paths can be variablized as follows:
- /animals/* - will match anything that starts with "animals/". "*" matches any number of path segments including zero segments (meaning "animals/" alone will match and so will "animals/dogs/fido"). "*" wildcards are only valid as the last segment in a path.
- /animals/dogs/:dogName - if a path segment starts with a ":" it indicates that the value can be anything but a value is required and should be mapped to the corresponding variable name, in this case "dogName", by whoever is doing the path matching.
- /animals/dogs/{fido|ralph|jackie} - if the path segment is wrapped in "{}" the contents are considered a regular expression
Patternfor matching - /animals/dogs/${fido|ralph|jackie} - a '$' can prefix '{}' as syntatic sugar some may be familiar with.
- /animals/dogs/{dogName:fido|ralph|jackie} - again a regex, this time with a variable binding to "dogName"
- /animals/[{dogs|cats|snakes}]/:animalName/* - if something is wrapped in square brackets "[]" that segment and all subsequent segments are optional. If the segments exists in the path being compared to, they must match the supplied rules, but if the comparison path ends right before the first optional segment, the paths still match.
When used in the context of a Api configuration you may see something like this:
Engine e = new Engine().withIncludeOn(null, new Path("/apis"));
.withApi(new Api().withIncludeOn(null, new Path("bookstore/{storeName:johnsBestBooks|carolsBooksOnMain}"))
.withEndpoint(new Endpoint().withIncludeOn(null, new Path("categories/:category/"))
.withAction(new BrowseCategoriesAction().withIncludeOn(null, new Path("[:subcategory]/*")))));
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidAddspartto the end of the Path.booleanConvenience overloading ofextract(Map, Path, boolean)withgreedy = true.Consumes the matching parts ofmatchingConcretePathand extracts any named variable tomatchingConcretePathif this any of this paths parts contain variable bindings.first()Simple way to pull the first element of the path without having to check forsize() > 0first.get(int index) Simple way to get element atindexwithout haveint to check forsize() > indexfirst.getVarName(int index) Extracts a variable name form the path expression ifindexexists and has a var name.booleanisOptional(int index) Square brackets, '[]', indicate that a path path (and by implication, all following parts) are considered optional for path matching.booleanisStatic(int index) Checks to see if the value atindexis a wildcard, a variable, or is optional.booleanisVar(int index) Check to see if the value atindexstarts with '${', '{', ':' after removing any leading '[' characters.booleanisWildcard(int index) Check if the path part atindexis equal to '*' without having to check ifsize() @lt; indexfirst.last()Simple way to pull the last element of the path without having to check forsize() > 0first.booleanChecks if this Path is as case insensitive match, including any optional rules, wildcards, and regexes toconcretePath.booleanConvenience overloading ofmatches(Path).parts()Gets the path parts as a List.remove(int index) Simple way to remove the path part atindexwithout having to check forsize() @lt; indexfirst.intsize()booleanstartsWith(List<String> partsToMatch) Performs a case insensitive string match between this Path andpathsToMatch.subpath(int fromIndex, int toIndex) Creates a new sub Path.toString()
-
Constructor Details
-
Path
public Path()Creates an empty Path -
Path
Creates a clone of the suppliedPath- Parameters:
path- the Path to be cloned
-
Path
Constructs a Path based on all of the suppliedparts.The strings in
partmay themselves contain "/" characters and will be split into multiple parts correspondingly. MeaningPath p = new Path("part1", "part2/part3", "/part4/", "////part5//part6/", "part7")is valid and would result in a Path with parts "part1", "part2", "part3", "part4", "part5", "part6", "part7".- Parameters:
part- an array of path part strings
-
Path
Convenience overload ofPath(String...).- Parameters:
parts- an list of path part strings
-
-
Method Details
-
parts
Gets the path parts as a List.Method signature could easily have been "asList()"
- Returns:
- a new list with the individual path parts n the originally defined case.
-
first
Simple way to pull the first element of the path without having to check forsize() > 0first.- Returns:
- the first element in the path if it exists otherwise null
-
last
Simple way to pull the last element of the path without having to check forsize() > 0first.- Returns:
- the last element in the path if it exists otherwise null
-
get
Simple way to get element atindexwithout haveint to check forsize() > indexfirst.- Parameters:
index- the index of the path part to retrive- Returns:
- the path part at index if it exists otherwise null
-
add
Addspartto the end of the Path.The
partsis exploded viaUtils.explode('/', part)first so while the part arg is a single value, it could result in multiple additions.- Parameters:
parts- path parts to add
-
remove
Simple way to remove the path part atindexwithout having to check forsize() @lt; indexfirst.- Parameters:
index- the index of the path part to remove- Returns:
- the path part previously located at
indexif it existed otherwise null
-
startsWith
Performs a case insensitive string match between this Path andpathsToMatch.Wildcards and regular expressions are not supported in this method, only straight case insensitive string comparison.
- Parameters:
partsToMatch- the path parts to to match against- Returns:
- true if each index of
partsToMatchis a case insensitive match to this Path at the same index otherwise false.
-
size
public int size()- Returns:
- the number of parts in the Path
-
toString
-
equals
-
subpath
Creates a new sub Path.- Parameters:
fromIndex- low endpoint (inclusive) of the subListtoIndex- high endpoint (exclusive) of the subList- Returns:
- a subpath from
fromIndex(inclusive) totoIndex(exclusive)
-
isStatic
public boolean isStatic(int index) Checks to see if the value atindexis a wildcard, a variable, or is optional.- Parameters:
index- the path part to check- Returns:
- true if the path part at
indexis a '*' char or starts with '[', '{' or ':'
-
isWildcard
public boolean isWildcard(int index) Check if the path part atindexis equal to '*' without having to check ifsize() @lt; indexfirst.- Parameters:
index- the path part to check- Returns:
- true if the path part at
index
-
isVar
public boolean isVar(int index) Check to see if the value atindexstarts with '${', '{', ':' after removing any leading '[' characters.- Parameters:
index- the index to check- Returns:
- true if the value exists and is variableized but not a wildcard, false otherwise.
-
getVarName
Extracts a variable name form the path expression ifindexexists and has a var name.'varName' would be extracted from
getVarName(1)for the following paths.- /part/:varName/
- /part/{varNam:regex}/
- /part/${varNam:regex}/
Square brackets indicating a path component is optioanl don't impact retrieval of the var name so the following would return the same as there above counterparts:
- /part/[:varName]/
- /[part]/{varNam:regex}]/
- /[part]/[${varNam:regex}]/
- Parameters:
index- the index of the var name to get- Returns:
- the variable name binding for the parth part at
indexif it exists
-
isOptional
public boolean isOptional(int index) Square brackets, '[]', indicate that a path path (and by implication, all following parts) are considered optional for path matching.For example:
new Path("first/second/[third]/").matches(new Path("first/second/third"))- Parameters:
index- the part part to check- Returns:
- true if the path part at
indexexists and starts with '[' and ends with ']'
-
matches
Convenience overloading ofmatches(Path).- Parameters:
toMatch- the path string to match- Returns:
- true if the paths match
-
matches
Checks if this Path is as case insensitive match, including any optional rules, wildcards, and regexes toconcretePath.As the name implies
concretePathis considered to be a literal path not containing optionals, wildcards, and regexes.As also documented above:
- paths can end with a "/*" character meaning this and all following parts are optional and unconstrained
- wrapping a path part in square brackets, '[]' indicates that it and all following part parts are optional.
- wrapping a path part in '${}' or '${}' indicates that this path part should match via a regular expression such as '${[0-9a-fA-F]{1,8}}' to match a 1 to 8 character alpha numeric part
- you can bind a variable name to a regex by preceding the regex with a name and a colon '/${id:[0-9a-fA-F]{1,8}}/'
- starting a path part with a ':' such as '/:id/' is functionally equivalent to '/${id:.*}'
All non regex comparisons are performed with String.equalsIgnoreCase.
All regexes are compiled with Pattern.CASE_INSENSITIVE.
- Parameters:
concretePath- the path to match against- Returns:
- true if this path matches
concretePath
-
extract
Convenience overloading ofextract(Map, Path, boolean)withgreedy = true.- Parameters:
params- a map to add extracted name/value pairs totoMatch- the path to extract from- Returns:
- the part of this path that matched
- See Also:
-
extract
Consumes the matching parts ofmatchingConcretePathand extracts any named variable tomatchingConcretePathif this any of this paths parts contain variable bindings.If
greedyis true, the match will consume through matching optional path parts.If
greedyis false, variable bindings in any optional paths parts will be extracted but the parts will not be removed frommatchingConcretePath.Here is an example:
Map params = new HashMap(); Path engineMatch = new Path("apis/myapi/*"); Path apiMatch = new Path("${version:v1|v2}/:tenant") Path endpointMatch = new Path("[${collection:books|categories|orders}]/*"); Path actionMatch = new Path("[:orderId]/*"); Path requestPath = new Path("/apis/myapi/v2/bobsBooks/orders/67890"); engineMatch.extract(requestPath); // params is empty, requestPath is now 'v2/bobsBooks/orders/67890' apiMatch.extract(requestPath); //version=v2 and tenant=bobsBooks have been added to params and requestPath is now 'orders/67890' endpointMatch.extract(requestPath); //collection=orders has been added to params and requestPath is now '67890' actionMatch.extract(requestPath); //orderId=67890 has been added to params and requestPath is now empty.The above example is very similar to how an
Engineprocesses paths when selecting an Api, Endpoint, and Actions to run.Engine will also add the params to the Request Url params as if they had been supplied as name value pairs by the caller on the query string.
- Parameters:
params- the map to add extracted name/value pairs tomatchingConcretePath- the path to extract fromgreedy- if extraction should consume through optional path parts- Returns:
- the same Path object that was passed in but potentially now shorter as matching segments may have been consumed
- See Also:
-