Hi Frank,
After your email to me i have a better understanding of what you meant
by resolving, which was an entirely different to what i thought it
meant, which is good. Marc and I have been using the term resolve to
obtain a Java object instance from a Java class. Now i understand that
by resolving you mean: given a URI resolve that URI from a given set of
URI templates.
Currently Jersey uses a naive algorithmic approach to URI resolving.
Each Resource class has an array of dispatchers, each dispatcher has a
URI template associated with it, and the array of dispatchers are
ordered according to the URI template ordering specified by JSR 311.
Resolving is implemented by iterating through the array of dispatchers
and performing a match of the URI path against each dispatcher. See
the com.sun.ws.rest.impl.model.BaseResourceClass#dispatch for specific
details.
Obviously such an approach does not scale for a web application with
many root resources and a resource with many URI templates for
sub-locator and sub-methods. Where as, if my understanding is correct,
the algorithm you have experimented with will scale much better.
We need to do some refactoring so that BaseResourceClass uses a
"UriResolver" interface rather than a list of dispatchers. The
UriResolver can operate on a set of a tuples of {URI template, T} where
T is a generic type. That way the interface and implementation(s) will
have more value. For use with BaseResourceClass the dispatcher can be
used for T. Something like the following is a rough sketch:
interface UriResolver<T> {
/**
* Add a template to the set of templates to resolve.
*
* @param template the URI template
* @param t the instance of a type associated with the template to be
* returned if a URI is resolved to the template.
* @return true if the template was added, otherwise false if there
is a duplicate
* template in the list.
*/
boolean add(UriTemplateType template, T t);
void clear();
Map<UriTemplateType, T> getTemplates();
/**
* Resolve a uri. This method can be used when the template
variables of a URI template
* are separated from the actual
*
* @param uri the uri
* @param rightHandPath the returned right hand path of the uri if
resolving
* succeeded.
* @param templateValues the returned linear list of template values
matching
* the template variables
* @return T the instance of a type associated with the resolved
uri, otherwise
* null if the uri could not be resolved
*/
T resolve(String uri, StringBuilder rightHandPath, List<String>
templateValues);
/**
* Resolve a uri.
*
* @param uri the uri
* @param rightHandPath the returned right hand path of the uri if
resolving
* succeeded.
* @param templateValues the returned map of template variables to
template values.
* @return T the instance of a type associated with the resolved
uri, otherwise
* null if the uri could not be resolved
*/
T resolve(String uri, StringBuilder rightHandPath, Map<String,
String> templateValues);
}
It would be good to use UriTemplateType (i would prefer UriTemplate but
that is the name of the annotation) as this can validate a URI template
so it is not up to the UriResolver to do so. Also other properties of
the template can be passed.
A UriResolver implementation needs to support:
- the ordering of the regular expressions produced from URI templates as
specified in JSR 311;
- the rules for processing the left-hand of the URI path and returning
the right-hand of the URI path for further processing by resources
returned by sub-locators;
- a limited/non-limited last template variable consuming all the
right-hand of the URI path; and
- the returning of URI template values and at the same we may be able to
fix an annoying bug related URI template matching [1], basically we need
to disassociated the template variable names from the matches of those
variables and be able to return a list of values.
IMHO the best thing to do is refactor using the existing resolving
implementation so we only change one thing at a time. That way we can
test the refactoring with the unit tests. When the unit tests pass we
can change the URI resolver implementation. Also since we have both
implementations we can show some simple performance tests on each
implementation directly.
What do you think?
Paul.
[1]
https://jersey.dev.java.net/issues/show_bug.cgi?id=1