users@jersey.java.net

[Jersey] Re: UriInfo injection at resource initialization time

From: Martin Matula <martin.matula_at_oracle.com>
Date: Thu, 10 Mar 2011 15:37:03 +0100

If you are accessing UriInfo when matching is not fully done - i.e. from
a sub-resource locator, you can detect it is not fully matched yet by
checking:
uriInfo.getPath().equals(uriInfo.getMatchedURIs().get(0))

Once the above returns true, the matched resource can be obtained from
uriInfo.getMatchedResources().get(0).

Martin

On 10.3.2011 14:34, Martynas Jusevicius wrote:
> Let me ask this way - how do you check that Resource is a leaf of the
> matching Resources tree (per-request)? I.e. request URI matches its
> URI template and will not match any of its subresources.
>
> On Thu, Mar 10, 2011 at 2:03 PM, Martin Matula<martin.matula_at_oracle.com> wrote:
>> Hi,
>> The solution I've attached below should not have the issue you are
>> mentioning.
>> Regarding your comment:
>>>> I think JAX-RS lacks means to retrieve URIs of (matching) resources,
>>>> as opposed to request URI.
>> It is impossible to do in general. Note the set of URI's matching a resource
>> can be infinite.
>> Martin
>>
>> public abstract class AbstractResource {
>> private Individual i;
>> AbstractResource() {
>> }
>>
>> AbstractResource(URI uri) {
>> initIndividual(uri);
>> }
>>
>> void initIndividual(URI uri) {
>> System.out.println(uri);
>> i = ///
>> }
>> }
>>
>> @Path("/")
>> @Singleton
>> public class TestRootResource extends AbstractResource {
>> private TestSubResource subResource;
>>
>> private synchronized void init(UriInfo uriInfo) {
>> if (subResource == null) {
>> initIndividual(uriInfo.getBaseUri());
>> subResource = new
>> TestSubResource(uriInfo.getBaseUriBuilder().path(TestSubResource.PATH).build());
>> }
>> }
>>
>> @GET
>> @Produces("text/plain")
>> public String doGet(@Context UriInfo uriInfo) {
>> init(uriInfo);
>> return "TestResource.doGet()";
>> }
>>
>> @Path(TestSubResource.PATH)
>> public TestSubResource getSubResource(@Context UriInfo uriInfo) {
>> init(uriInfo);
>> return subResource;
>> }
>> }
>>
>> // no annotations needed here
>> public class TestSubResource extends AbstractResource {
>> public static final String PATH = "sub";
>>
>> TestSubResource(URI uri) {
>> super(uri);
>> }
>>
>> @GET
>> @Produces("text/plain")
>> public String doGet() {
>> return "TestSubResource.doGet()";
>> }
>> }
>>
>>
>> On 10.3.2011 13:42, Martynas Jusevicius wrote:
>>> Martin,
>>>
>>> I ran into another issue. As UriInfo in Resource constructors
>>> represents request URI and not Resource URI, and it gets passed up the
>>> subresource chain, I can only use it for initialization when I know
>>> that this is actually the matching Resource (the end of the chain).
>>>
>>> public Resource(Resource parent, @Context UriInfo uriInfo)
>>> {
>>> super(parent);
>>> this.uriInfo = uriInfo;
>>> System.out.println(this + " " + uriInfo.getAbsolutePath());
>>> // do some initialization using absolute Resource URI
>>> // setIndividual(uriInfo.getAbsolutePath());
>>> }
>>>
>>> frontend.controller.resource.FrontPageResource_at_be843c
>>> http://localhost:8084/ontologies/sioc/classes/Item
>>> frontend.controller.resource.ontology.OntologyListResource_at_c6173f
>>> http://localhost:8084/ontologies/sioc/classes/Item
>>> frontend.controller.resource.ontology.OntologyResource_at_1698552
>>> http://localhost:8084/ontologies/sioc/classes/Item
>>> frontend.controller.resource.ontology.OntologyClassListResource_at_974121
>>> http://localhost:8084/ontologies/sioc/classes/Item
>>> frontend.controller.resource.class_.ClassResource_at_1b7a9c1
>>> http://localhost:8084/ontologies/sioc/classes/Item
>>>
>>> The ClassResource is the one that matches the URI. So would it be a
>>> solution to discard the previous constructor calls by checking
>>>
>>> if (this == uriInfo.getMatchedResources().get(0))
>>> setIndividual(uriInfo.getAbsolutePath())
>>>
>>> But debugging I can't really see if the matching Resource goes into
>>> matchedResources, so maybe it's better like this if it doesn't
>>>
>>> if (!uriInfo.getMatchedResources().contains(this))
>>> setIndividual(uriInfo.getAbsolutePath())
>>>
>>> I hope you get what I mean :)
>>>
>>> I think JAX-RS lacks means to retrieve URIs of (matching) resources,
>>> as opposed to request URI.
>>>
>>> Martynas
>>>
>>> On Wed, Mar 9, 2011 at 7:06 PM, Martin Matula<martin.matula_at_oracle.com>
>>> wrote:
>>>> I see, if you have a property with the base uri, then it is probably
>>>> easiest
>>>> to do everything in the constructor of your root resource.
>>>> Martin
>>>>
>>>> On 9.3.2011 18:59, Martynas Jusevicius wrote:
>>>>> Thanks.
>>>>>
>>>>> I would have to do the whole model in one go, because the
>>>>> representation methods of the root resource are already going to run
>>>>> queries on it.
>>>>>
>>>>> Do you think it's a better idea than storing base URI in some property
>>>>> file and using say ServletContextListener for initialization?
>>>>>
>>>>> On Wed, Mar 9, 2011 at 6:42 PM, Martin Matula<martin.matula_at_oracle.com>
>>>>> wrote:
>>>>>> Either you can lazily initialize the Individuals in your resources -
>>>>>> i.e.
>>>>>> getIndividual() method can take UriInfo as a parameter and can lazily
>>>>>> initialize the individual instance variable if it is null, and return
>>>>>> its
>>>>>> content otherwise (this would have to be in a synchronized block):
>>>>>> public abstract class AbstractResource {
>>>>>> private Individual i;
>>>>>>
>>>>>> public synchronized Individual getIndividual(UriInfo uriInfo) {
>>>>>> if (i == null) {
>>>>>> i = new Individual(uriInfo.getAbsolutePath());
>>>>>> }
>>>>>> return i;
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> @Path("/")
>>>>>> @Singleton
>>>>>> public class TestRootResource extends AbstractResource {
>>>>>> @GET
>>>>>> @Produces("text/plain")
>>>>>> public String doGet(@Context UriInfo uriInfo) {
>>>>>> return "TestResource.doGet() - Individual: " +
>>>>>> getIndividual(uriInfo);
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> @Path("/sub")
>>>>>> @Singleton
>>>>>> public class TestSubResource extends AbstractResource {
>>>>>> @GET
>>>>>> @Produces("text/plain")
>>>>>> public String doGet(@Context UriInfo uriInfo) {
>>>>>> return "TestSubResource.doGet() - Individual: " +
>>>>>> getIndividual(uriInfo);
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> Or you can do eager initialization of the whole model on the first
>>>>>> request
>>>>>> and use subresource locators - e.g. this should work:
>>>>>>
>>>>>> public abstract class AbstractResource {
>>>>>> private Individual i;
>>>>>> AbstractResource() {
>>>>>> }
>>>>>>
>>>>>> AbstractResource(URI uri) {
>>>>>> initIndividual(uri);
>>>>>> }
>>>>>>
>>>>>> void initIndividual(URI uri) {
>>>>>> System.out.println(uri);
>>>>>> i = ///
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> @Path("/")
>>>>>> @Singleton
>>>>>> public class TestRootResource extends AbstractResource {
>>>>>> private TestSubResource subResource;
>>>>>>
>>>>>> private synchronized void init(UriInfo uriInfo) {
>>>>>> if (subResource == null) {
>>>>>> initIndividual(uriInfo.getAbsolutePath());
>>>>>> subResource = new
>>>>>>
>>>>>>
>>>>>> TestSubResource(uriInfo.getAbsolutePathBuilder().path(TestSubResource.PATH).build());
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> @GET
>>>>>> @Produces("text/plain")
>>>>>> public String doGet(@Context UriInfo uriInfo) {
>>>>>> init(uriInfo);
>>>>>> return "TestResource.doGet()";
>>>>>> }
>>>>>>
>>>>>> @Path(TestSubResource.PATH)
>>>>>> public TestSubResource getSubResource(@Context UriInfo uriInfo) {
>>>>>> init(uriInfo);
>>>>>> return subResource;
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> // no annotations needed here
>>>>>> public class TestSubResource extends AbstractResource {
>>>>>> public static final String PATH = "sub";
>>>>>>
>>>>>> TestSubResource(URI uri) {
>>>>>> super(uri);
>>>>>> }
>>>>>>
>>>>>> @GET
>>>>>> @Produces("text/plain")
>>>>>> public String doGet() {
>>>>>> return "TestSubResource.doGet()";
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> Hope this helps.
>>>>>> Martin
>>>>>>
>>>>>> On 9.3.2011 18:06, Martynas Jusevicius wrote:
>>>>>>> Sorry Martin, you're right! Base URI was set on each request...
>>>>>>>
>>>>>>> I was so fixated on getting UriInfo to work and use it to lookup
>>>>>>> resources in the RDF model that I forgot that model had to be
>>>>>>> initialized in the first place.
>>>>>>>
>>>>>>> Now I see what you're saying - since I need absolute URIs to
>>>>>>> initialize RDF and they cannot be resolved without base URI, this
>>>>>>> needs to be done within the request context. This is not even JAX-RS
>>>>>>> specific, it's just that I'm implementing RDF and JAX-RS at the same
>>>>>>> time..
>>>>>>>
>>>>>>> And when I have the base URI of the request, I can build an absolute
>>>>>>> one using UriBuilder.fromResource(class).build(), right?
>>>>>>> The question is, where should I put the initialization? In @GET of the
>>>>>>> root Resource and mark it with some flag so it only runs once?
>>>>>>> Or is there a better hook for that?
>>>>>>>
>>>>>>> Martynas
>>>>>>>
>>>>>>> On Wed, Mar 9, 2011 at 5:01 PM, Martin
>>>>>>> Matula<martin.matula_at_oracle.com>
>>>>>>> wrote:
>>>>>>>> I still don't see how that gets you any more further than
>>>>>>>> UriBuilder.fromResource(class).build().
>>>>>>>> The root resource needs to figure out the server name, port, context
>>>>>>>> path
>>>>>>>> and server mapping. How did you get that without the request context?
>>>>>>>> If you figured out how to get the "base URI" it for your servlet
>>>>>>>> outside
>>>>>>>> of
>>>>>>>> the request context, you can do the same thing for your JAX-RS
>>>>>>>> resources
>>>>>>>> and
>>>>>>>> then just do
>>>>>>>> UriBuilder.fromUri(baseUri).path(Resource.class).build().
>>>>>>>> Martin
>>>>>>>>
>>>>>>>> On 9.3.2011 16:49, Martynas Jusevicius wrote:
>>>>>>>>> I had a recursive Resource.getAbsolutePath() which went up the
>>>>>>>>> parent
>>>>>>>>> tree concatenating getPath().
>>>>>>>>>
>>>>>>>>> For singletons I could get the URI like this:
>>>>>>>>> SearchResource.getInstance().getAbsolutePath().
>>>>>>>>>
>>>>>>>>> For other Resources the mapping happened within the request.
>>>>>>>>>
>>>>>>>>> On Wed, Mar 9, 2011 at 4:31 PM, Martin
>>>>>>>>> Matula<martin.matula_at_oracle.com>
>>>>>>>>> wrote:
>>>>>>>>>> Hi Martynas,
>>>>>>>>>>
>>>>>>>>>> On 9.3.2011 15:59, Martynas Jusevicius wrote:
>>>>>>>>>>>>> I had achieved the same using abstract Resource superclass (like
>>>>>>>>>>>>> in
>>>>>>>>>>>>> my
>>>>>>>>>>>>> last example) with
>>>>>>>>>>>>> - getPath() and getAbsolutePath() equivalents
>>>>>>>>>>>>> - constructor Resource(Resource parent) - effectively building a
>>>>>>>>>>>>> parent/child tree of Resource instances
>>>>>>>>>>>>> - Servlet-like doGet(), doPost() etc methods
>>>>>>>>>>>>> and the real HttpServlet mapping request URIs to Resource
>>>>>>>>>>>>> instances
>>>>>>>>>>>>> and executing the appropriate do..() methods.
>>>>>>>>>> I mean, how did you get the absolute URI outside of the request
>>>>>>>>>> context?
>>>>>>>>>> I
>>>>>>>>>> am guessing all the above initialization happened upon the first
>>>>>>>>>> request
>>>>>>>>>> within it's context, no?
>>>>>>>>>> Martin
>>>>>>>>>>
>>>>>>>>>>