Class McpUriTemplateMatcher
A template is compiled once into an immutable matcher that exposes:
isReverseMatchable()- whether the template is one of the settled reversible forms (simple, reserved, fragment, path, label, or query scalar expressions, with no explode/prefix modifier and no ambiguous adjacency to another expression);literalOctetCount()- the number of normalized literal octets outside{...} expressions, for registry specificity ranking;variableCount()andvariableNames()- the declared template variables, in declaration order; andmatch(String)- reverse-matches a concrete URI against a reverse-matchable template, returning an immutable, insertion-ordered, percent-decoded variable map, ornull if the URI does not match.
Reverse-matchable forms:
Non-explode, non-prefix simple scalar match(String) always returns
Percent-encoding normalization:
Matching and literal-specificity counting follow RFC 3986 percent-normalization implemented fresh by this
class: valid application/x-www-form-urlencoded plus-as-space semantics).
A concrete URI with a malformed percent escape, or a capture whose decoded bytes are not valid UTF-8, never
matches. This class deliberately does not reuse
org.apache.juneau.commons.utils.StringUtils
Ambiguous-capture resolution:
A reversible template compiles to an alternating sequence of literal and capture pieces; because an
expression with ambiguous adjacency to another expression is rejected as non-reverse-matchable (see above),
a capture piece in a reverse-matchable template is always immediately followed by either a literal piece or
the end of the template, never by another capture. When a reserved/fragment (unbounded) or path/label/simple
(bounded-by-match(String) resolves the
capture's length via a single longest-to-shortest search for the position at which that immediately-following
literal text occurs, using String.lastIndexOf(String, int). This deterministically implements "the
longest capture that still permits the (immediately following) literal to match" without whole-suffix
backtracking across multiple capture/literal boundaries, which keeps matching a bounded, linear-in-input scan
per capture with no regex-style catastrophic backtracking risk, at the cost of not re-trying an earlier
capture's length choice if a later, unrelated piece of the template fails to match. That scope narrowing is
intentional and consistent with this matcher covering reliable inversion of a narrow subset, not a complete
RFC 6570 engine.
Scope:
This matcher is intentionally MCP-local. It is not registered as a general-purpose RFC 3986/6570 utility;
if a second real consumer outside MCP resource templates needs equivalent percent-normalization or
URI-template parsing, that would justify extracting a shared helper into juneau-commons at that time,
not before.
-
Method Summary
Modifier and TypeMethodDescriptionstatic McpUriTemplateMatcherParses and compiles a single RFC 6570 URI template.booleanWhether this template is one of C4's reversible forms and therefore eligible for template-backed reads.intThe count of normalized literal URI octets outside{...} expressions.Reverse-matches a concrete URI against this template.template()The original source template this matcher was compiled from.intThe number of distinct variables declared by this template.The variables declared by this template, in declaration order.
-
Method Details
-
compile
Parses and compiles a single RFC 6570 URI template.Registration syntax is validated independently of reverse-matchability: a syntactically legal template outside the reversible subset compiles successfully with
isReverseMatchable()returningfalse , so it remains listable and completable even thoughmatch(String)always returnsnull for it.- Parameters:
uriTemplate- The URI template to compile. Must not benull or blank.- Returns:
- A new compiled matcher.
- Throws:
IllegalArgumentException- If the template isnull /blank, has malformed braces, has a malformed percent escape, has invalid operator/varspec grammar, has a literal segment containing an invalid UTF-8 percent-escape sequence, or declares the same variable name more than once.
-
template
The original source template this matcher was compiled from.- Returns:
- The original template string. Never
null .
-
isReverseMatchable
Whether this template is one of C4's reversible forms and therefore eligible for template-backed reads.- Returns:
true ifmatch(String)can ever return a non-null result.
-
literalOctetCount
The count of normalized literal URI octets outside{...} expressions.A normalized percent triplet counts as one literal octet, not three source characters. This is exposed purely as ranking metadata; this class applies no ranking itself. Registry code performing final ranking must not invent additional tie-breakers (operator type, capture width, or value length) beyond this count,
variableCount(), and registration order.- Returns:
- The literal octet count.
-
variableCount
The number of distinct variables declared by this template.- Returns:
- The declared variable count.
-
variableNames
The variables declared by this template, in declaration order.Populated regardless of
isReverseMatchable(), so variables of a valid-but-not-reverse-matchable template remain available for exact-template-string completion lookups.- Returns:
- An immutable, insertion-ordered list of declared variable names. Never
null .
-
match
Reverse-matches a concrete URI against this template.- Parameters:
uri- The concrete URI to match. Can benull , in which case this method returnsnull .- Returns:
- An immutable, insertion-ordered, UTF-8-decoded map of variable name to decoded value, in
declaration order, or
null if this template is notreverse-matchable, the URI does not match, the URI contains a malformed percent escape, or a captured value's decoded bytes are not valid UTF-8.
-