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 14:03:35 +0100

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