users@jax-rs-spec.java.net

[jax-rs-spec users] [jsr339-experts] Re: Re: Re: Re: Re: FYI: ResourceContext API proposed

From: Marek Potociar <marek.potociar_at_oracle.com>
Date: Thu, 30 Aug 2012 15:23:02 +0200

On Aug 29, 2012, at 4:09 PM, Bill Burke <bburke_at_redhat.com> wrote:

>
>
> On 8/29/2012 9:54 AM, Marek Potociar wrote:
>>
>> On Aug 29, 2012, at 2:47 PM, Bill Burke <bburke_at_redhat.com
>> <mailto:bburke_at_redhat.com>> wrote:
>>
>>>
>>>
>>> On 8/29/2012 8:15 AM, Marek Potociar wrote:
>>>>
>>>> On Aug 28, 2012, at 8:40 PM, Bill Burke <bburke_at_redhat.com
>>>> <mailto:bburke_at_redhat.com>
>>>> <mailto:bburke_at_redhat.com>> wrote:
>>>>
>>>>>
>>>>>
>>>>> On 8/28/2012 12:43 PM, Marek Potociar wrote:
>>>>>>
>>>>>> In Jersey users typically use it to provision (fully-initialized and
>>>>>> properly scoped) sub-resource instances
>>>>>
>>>>> I just not certain this is a job for JAX-RS.
>>>>>
>>>>>> , regardless of what container
>>>>>> manages each particular instance, using the
>>>>>> ResourceContext.getResource(...) method. Another problem the users are
>>>>>> facing is that in many cases if a user wants to support more
>>>>>> complex URI
>>>>>> spaces, it would make a lot of sense to leverage the JAX-RS matching
>>>>>> engine to internally "find" a proper resource instance or information
>>>>>> about it. For those cases the ResourceContext contains the matchXxx()
>>>>>> methods that expose the matching engine to the end user.
>>>>>>
>>>>>
>>>>> I've had the case that we implemeted where users want to do something
>>>>> like a Servlet.forward(), but I don't think this is the same thing.
>>>>> Can you give some examples of each match method? I'm just not
>>>>> understanding how it would be used.
>>>>
>>>> I'll borrow the example from a recent post on our users forum:
>>>>
>>>> Let's say you have a bookstore application that let you access books
>>>> (book resources) via various URI schemes, e.g.:
>>>>
>>>> /bookstore/books/{bid}
>>>> /bookstore/sections/{section}/books/{sbid}
>>>> /bookstore/authors/{author}/books/{abid}
>>>> ...
>>>>
>>>> Ideally, you want to have just a single BooksResource that handles all
>>>> these URIs. So from sub-resource locators in your SectionsResource and
>>>> AuthorsResource you could use the ResourceContext.matchXxx() methods to
>>>> "find" the (properly initialized) instance of BooksResource without
>>>> having to know too much about it. All you need to know is the main entry
>>>> point to all books and the book ID. E.g.:
>>>>
>>>> @Path("books/{id}")
>>>> public class BooksResource {
>>>> ...
>>>> BooksResource getBook() { ... }
>>>> }
>>>>
>>>>
>>>> @Path("authors")
>>>> public class AuthorsResource {
>>>> ...
>>>> @Path("{author}/books/{abid}")
>>>> BooksResource getBook(@Context ResourceContext rc, ...) {
>>>> String bookId = ... ; // get the book UID
>>>> return
>>>> rc.matchResource(UriBuilder.fromResource(BooksResource.class).pathParam("id",
>>>> bookId).build());
>>>> }
>>>> }
>>>>
>>>
>>>
>>> It would be much simpler to implement this as:
>>>
>>> @Path("/books") // ignored by subresource locator
>>> public class BooksResource {
>>>
>>> protected String Author author;
>>>
>>> public BooksResource () {}
>>>
>>> public BooksResource(String author) {
>>> this.author = author;
>>> }
>>>
>>> @GET
>>> public List<Books> getBooks() {
>>> if (author != null) {...}
>>> else {...}
>>> }
>>>
>>> @Path("{id}")
>>> @GET
>>> public Book getBook(@PathParam("id") bookId)
>>>
>>>
>>> @Path("/author")
>>> public AuthorsResource getAuthor() {
>>> return new AuthorsResource();
>>> }
>>> }
>>>
>>> @Path("/authors")
>>> public class AuthorsResource {
>>>
>>> @Path("{id}")
>>> @GET
>>> public Author getAuthor(@PathParam("id")...) {...}
>>>
>>> ...
>>> @Path("{author}/books")
>>> BooksResource getBook(@PathParam("author") author) {
>>> return new BooksResource(author);
>>> }
>>> }
>>>
>>
>> You need to take my simplistic example with a grain of salt. In any
>> case, what you wrote above demonstrates the problem as the above is
>> exactly what users seem to complain about all the time, because:
>>
>> * they don't want to repeat themselves and inject values into SRL
>> methods just to pass the values to the returned sub-resource if
>> these could be automatically injected by the framework.
>> * the sub-resource may be relying on larger amount of injectable data
>> making the case above just worse
>> * the scope of the matched resource may be different from the default
>> one and the resources can be managed by different containers but
>> there is no common API to provide the proper way how to access these
>> resources
>> * users sometimes just want to match particular URIs to see if there
>> are some specific related resources available and based on that
>> information decide what to do next, but there's no API that would
>> expose the matching engine to the users at the moment so are either
>> forced to use the proprietary extensions or implement the matching
>> themselves
>
> I don't agree with your assessment on injection. CDI, Spring, Guice, or EJB could be used just as easily. I don't see why we need an abstraction for injection especially when CDI exists in Java EE. I would absolutely support a Servlet.forward() mechanism, but I'm still not convinced this current feature is a good direction. I'd like to hear feedback from others, especially Sergey.

No it couldn't IMHO. Not if we are talking about proper injection of JAX-RS resources managed by those containers based on a URI information different from the one of the current request.

> I also don't think users would be interested in matching if they had forward() functionality.

Well, this feature was added to Jersey based on user requests, with a contribution from an external Jersey committer and we see it being frequently used. So there must be some users who need/want the feature.

>
>>>> Obviously, you can use those methods to conveniently support URI graphs
>>>> - from books resource you could easily navigate to authors or sections
>>>> etc. Other, more advanced scenarios are possible too. Among the main
>>>> advantages is that you don't need to know too much about the
>>>> implementation details and initialization of those other resource and
>>>> that you can avoid internal redirects.
>>>>
>>>
>>> I'm not seeing it. Your use case is already supported by the spec and
>>> also does not work very well for this:
>>>
>>> GET /authors/billburke/books
>>>
>>
>> I'm sure you see how the example could be extended to support that...
>> e.g. rc.matchResource("books/billburke")
>>
>
> No, I don't. How could you keep using the BooksResource class? You don't have the author information to perform the correct query and build of the returned book collection.

Sorry - it should have been "books?author=billburke" or similar.

>
>>>
>>> Also, (I'm not sure!) ResourceContext would not be able to have a
>>> portable implementation because I don't think you would be able to
>>> determine/resolve EJB references.
>>
>> You're right - this is one of the areas we need to focus on next. We
>> need to work with EJB guys to provide standard hooks for EJB lookup.
>> Nevertheless, while the solution would not be portable, it would still
>> be useful to have it as it unifies the resource lookup API for the
>> JAX-RS users and saves them a lot of headache.
>>
>
> This may be supported already in CDI Beanmanager. I'll ask my CDI guys.

I don't think it is, but it would be good if it was... Let us know.

Marek

>
> --
> Bill Burke
> JBoss, a division of Red Hat
> http://bill.burkecentral.com