Class Path

  • All Implemented Interfaces:
    java.lang.Comparable<Path>

    public class Path
    extends java.lang.Object
    implements java.lang.Comparable<Path>
    A case insensitive utility abstraction for working with forward slash based paths /like/you/find/in/urls.

    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 Pattern for 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 
      Constructor Description
      Path()
      Creates an empty Path
      Path​(Path path)
      Creates a clone of the supplied Path
      Path​(java.lang.String... part)
      Constructs a Path based on all of the supplied parts.
      Path​(java.util.List<java.lang.String> parts)
      Convenience overload of Path(String...).
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      Path add​(java.lang.String parts)
      Adds part to the end of the Path.
      Path chop()  
      int compareTo​(Path o)  
      Path copy()
      Return a new path that is an exactly copy of this one.
      Path copyFrom​(Path path)  
      boolean endsWithWildcard()  
      boolean equals​(java.lang.Object o)  
      static java.util.List<Path> expandOptionals​(java.util.List<Path> paths)  
      Path extract​(java.util.Map params, Path toMatch)
      Convenience overloading of extract(Map, Path, boolean) with greedy = true.
      Path extract​(java.util.Map params, Path matchingConcretePath, boolean greedy)
      Consumes the matching parts of matchingConcretePath and extracts any named variable to matchingConcretePath if this any of this paths parts contain variable bindings.
      static java.util.List<Path> filterDuplicates​(java.util.List<Path> paths)  
      java.lang.String first()
      Simple way to pull the first element of the path without having to check for size() > 0 first.
      java.lang.String get​(int index)
      Simple way to get element at index without haveint to check for size() > index first.
      java.lang.String getRegex​(int index)  
      static java.lang.String getRegex​(java.lang.String part)  
      java.util.List<Path> getSubPaths()
      Creates a list of all subpaths breaking before each optional segment Ex:
      java.lang.String getTemplate()  
      int getVarIndex​(java.lang.String varName)  
      java.lang.String getVarName​(int index)
      Extracts a variable name form the path expression if index exists and has a var name.
      boolean hasAllVars​(java.lang.String... vars)  
      boolean hasAnyVars​(java.lang.String... vars)  
      int hashCode()  
      boolean hasVars()  
      boolean isOptional​(int index)
      Square brackets, '[]', indicate that a path path (and by implication, all following parts) are considered optional for path matching.
      static boolean isOptional​(java.lang.String part)  
      boolean isStatic​(int index)
      Checks to see if the value at index is a wildcard, a variable, or is optional.
      boolean isVar​(int index)
      Check to see if the value at index starts with '${', '{', ':' after removing any leading '[' characters.
      static boolean isVar​(java.lang.String part)  
      boolean isWildcard()  
      boolean isWildcard​(int index)
      Check if the path part at index is equal to '*' without having to check if size() @lt; index first.
      static boolean isWildcard​(java.lang.String part)  
      java.lang.String last()
      Simple way to pull the last element of the path without having to check for size() > 0 first.
      boolean matches​(Path toMatch)
      Checks if this Path is a case insensitive match, including any optional rules, wildcards, and regexes to concretePath.
      boolean matches​(Path toMatch, boolean bidirectional)  
      boolean matches​(java.lang.String toMatch)
      Convenience overloading of matches(Path).
      static java.util.List<Path> materializeTrivialRegexes​(java.util.List<Path> paths)  
      java.util.List<java.lang.String> parts()
      Gets the path parts as a List.
      java.lang.String remove​(int index)
      Simple way to remove the path part at index without having to check for size() @lt; index first.
      Path removeLast()  
      boolean removeTrailingWildcard()  
      Path set​(int index, java.lang.String part)  
      void setOptional​(int index, boolean optional)  
      int size()  
      boolean startsWith​(java.util.List<java.lang.String> partsToMatch)
      Performs a case insensitive string match between this Path and pathsToMatch.
      Path subpath​(int fromIndex, int toIndex)
      Creates a new sub Path.
      java.lang.String toString()  
      static java.lang.String unwrapOptional​(java.lang.String part)  
      • Methods inherited from class java.lang.Object

        clone, finalize, getClass, notify, notifyAll, wait, wait, wait
    • Constructor Detail

      • Path

        public Path()
        Creates an empty Path
      • Path

        public Path​(Path path)
        Creates a clone of the supplied Path
        Parameters:
        path - the Path to be cloned
      • Path

        public Path​(java.lang.String... part)
        Constructs a Path based on all of the supplied parts.

        The strings in part may themselves contain "/" characters and will be split into multiple parts correspondingly. Meaning Path 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

        public Path​(java.util.List<java.lang.String> parts)
        Convenience overload of Path(String...).
        Parameters:
        parts - an list of path part strings
    • Method Detail

      • getTemplate

        public java.lang.String getTemplate()
      • expandOptionals

        public static java.util.List<Path> expandOptionals​(java.util.List<Path> paths)
      • filterDuplicates

        public static java.util.List<Path> filterDuplicates​(java.util.List<Path> paths)
      • materializeTrivialRegexes

        public static java.util.List<Path> materializeTrivialRegexes​(java.util.List<Path> paths)
      • copyFrom

        public Path copyFrom​(Path path)
      • copy

        public Path copy()
        Return a new path that is an exactly copy of this one.
        Returns:
      • parts

        public java.util.List<java.lang.String> 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

        public java.lang.String first()
        Simple way to pull the first element of the path without having to check for size() > 0 first.
        Returns:
        the first element in the path if it exists otherwise null
      • last

        public java.lang.String last()
        Simple way to pull the last element of the path without having to check for size() > 0 first.
        Returns:
        the last element in the path if it exists otherwise null
      • get

        public java.lang.String get​(int index)
        Simple way to get element at index without haveint to check for size() > index first.
        Parameters:
        index - the index of the path part to retrive
        Returns:
        the path part at index if it exists otherwise null
      • add

        public Path add​(java.lang.String parts)
        Adds part to the end of the Path.

        The parts is exploded via Utils.explode('/', part) first so while the part arg is a single value, it could result in multiple additions.

        Parameters:
        parts - path parts to add
      • set

        public Path set​(int index,
                        java.lang.String part)
      • chop

        public Path chop()
      • remove

        public java.lang.String remove​(int index)
        Simple way to remove the path part at index without having to check for size() @lt; index first.
        Parameters:
        index - the index of the path part to remove
        Returns:
        the path part previously located at index if it existed otherwise null
      • removeLast

        public Path removeLast()
      • removeTrailingWildcard

        public boolean removeTrailingWildcard()
        Returns:
        true if this Path ended in a "*" which was removed, false if this Path does not end in a "*"
      • endsWithWildcard

        public boolean endsWithWildcard()
        Returns:
        true if this Path ends with a "*"
      • startsWith

        public boolean startsWith​(java.util.List<java.lang.String> partsToMatch)
        Performs a case insensitive string match between this Path and pathsToMatch.

        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 partsToMatch is 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

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object
        Returns:
        a pretty printed "/" separated path string representation
      • hashCode

        public int hashCode()
        Overrides:
        hashCode in class java.lang.Object
      • compareTo

        public int compareTo​(Path o)
        Specified by:
        compareTo in interface java.lang.Comparable<Path>
      • equals

        public boolean equals​(java.lang.Object o)
        Overrides:
        equals in class java.lang.Object
        Returns:
        true of the objects string representations match
      • unwrapOptional

        public static java.lang.String unwrapOptional​(java.lang.String part)
      • subpath

        public Path subpath​(int fromIndex,
                            int toIndex)
        Creates a new sub Path.
        Parameters:
        fromIndex - low endpoint (inclusive) of the subList
        toIndex - high endpoint (exclusive) of the subList
        Returns:
        a subpath from fromIndex (inclusive) to toIndex (exclusive)
      • isStatic

        public boolean isStatic​(int index)
        Checks to see if the value at index is a wildcard, a variable, or is optional.
        Parameters:
        index - the path part to check
        Returns:
        true if the path part at index is a '*' char or starts with '[', '{' or ':'
      • isWildcard

        public boolean isWildcard​(int index)
        Check if the path part at index is equal to '*' without having to check if size() @lt; index first.
        Parameters:
        index - the path part to check
        Returns:
        true if the path part at index
      • isWildcard

        public static boolean isWildcard​(java.lang.String part)
      • isWildcard

        public boolean isWildcard()
        Returns:
        true if this path equals "*"
      • isVar

        public boolean isVar​(int index)
        Check to see if the value at index starts 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.
      • isVar

        public static boolean isVar​(java.lang.String part)
      • getVarName

        public java.lang.String getVarName​(int index)
        Extracts a variable name form the path expression if index exists 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 index if it exists
      • getRegex

        public java.lang.String getRegex​(int index)
      • getRegex

        public static java.lang.String getRegex​(java.lang.String part)
      • 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 index exists and starts with '[' and ends with ']'
      • isOptional

        public static boolean isOptional​(java.lang.String part)
      • setOptional

        public void setOptional​(int index,
                                boolean optional)
      • matches

        public boolean matches​(java.lang.String toMatch)
        Convenience overloading of matches(Path).
        Parameters:
        toMatch - the path string to match
        Returns:
        true if the paths match
      • matches

        public boolean matches​(Path toMatch)
        Checks if this Path is a case insensitive match, including any optional rules, wildcards, and regexes to concretePath.

        As the name implies concretePath is 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:
        toMatch - the path to match against
        Returns:
        true if this path matches concretePath
      • matches

        public boolean matches​(Path toMatch,
                               boolean bidirectional)
      • extract

        public Path extract​(java.util.Map params,
                            Path toMatch)
        Convenience overloading of extract(Map, Path, boolean) with greedy = true.
        Parameters:
        params - a map to add extracted name/value pairs to
        toMatch - the path to extract from
        Returns:
        the part of this path that matched
        See Also:
        extract(Map, Path, boolean)
      • extract

        public Path extract​(java.util.Map params,
                            Path matchingConcretePath,
                            boolean greedy)
        Consumes the matching parts of matchingConcretePath and extracts any named variable to matchingConcretePath if this any of this paths parts contain variable bindings.

        If greedy is true, the match will consume through matching optional path parts.

        If greedy is false, variable bindings in any optional paths parts will be extracted but the parts will not be removed from matchingConcretePath.

        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.
         

        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 to
        matchingConcretePath - the path to extract from
        greedy - 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
      • getVarIndex

        public int getVarIndex​(java.lang.String varName)
      • hasVars

        public boolean hasVars()
      • hasAllVars

        public boolean hasAllVars​(java.lang.String... vars)
      • hasAnyVars

        public boolean hasAnyVars​(java.lang.String... vars)
      • getSubPaths

        public java.util.List<Path> getSubPaths()
        Creates a list of all subpaths breaking before each optional segment Ex:
             a/b[c]/d/[e]/*
         
        Becomes:
             a/b
             a/b/c/d
             a/b/c/d/e/*
         
        Returns:
        a list of all valid paths