On Aug 26, 2008, at 11:15 PM, Arul Dhesiaseelan wrote:
> Paul,
>
> Thanks for your inputs.
>
> I will use the PerSession annotation as per your suggestion. Is it
> available as part of .10 snapshots?
>
Yes.
Paul.
> -Arul
>
> Paul Sandoz wrote:
>> Hi Arul,
>>
>> A session is per-client. If you have multiple clients then each
>> will have a session and their own set of session attributes.
>>
>> Thus if you use a singleton as you propose (and it did what you
>> expected) it would not give the behavior you require for multiple
>> clients.
>>
>> Consider this:
>>
>> 1) Client 1 makes a first request to the service. The singleton
>> gets instantiated. The client 1 session does not exist, it is
>> created and initiated.
>>
>> 2) Client 2 makes the second request to the service. The singleton
>> is already instantiated. The client 2 session does
>> not exist and is not initiated.
>>
>> A way you can test this scenario in a browser is to delete
>> cookies. Make a request (client 1), delete the cookies, make
>> another request (client 2).
>>
>> So IIUC what you require is a resource class instance created per-
>> session.
>>
>> @PerSession
>> public static class ModelResource {
>> String currentModel = "defaultModel";
>>
>> @Produces("text/plain")
>> @GET
>> public String get() {
>> return currentModel;
>> }
>> }
>>
>> An instance of ModelResource will be stored in the session
>> attributes. Notice that you do not need to utilize the servlet
>> session itself. Of course if other resources utilize session you
>> could obtain the ModelResource from the session as well (using the
>> class name as the key). Care also has to be taken that such
>> classes are serializable such that they can be used in clustering
>> set ups.
>>
>>
>> Note that i think there are ways one can do this without utilizing
>> sessions making use of URIs/resources for users and the default
>> model, and using HTTP authentication with SSL. But i can
>> understand why utilizing session is so convenient. I think it
>> would be interesting to develop an such an example as this could
>> help developers evaluate better which directions to take.
>>
>> Paul.
>>
>> On Aug 25, 2008, at 7:15 PM, Arul Dhesiaseelan wrote:
>>
>>> Hi Paul,
>>>
>>> Thanks for revisiting this post.
>>>
>>> As per my understanding, @Singleton enforces that there can be
>>> only one instance of this resource in the web application
>>> context. So, I added this annotation to my resource so multiple
>>> instances do not get created for each client request.
>>>
>>> Let me explain my use case briefly so that you can correct me if
>>> I am doing something fundamentally wrong.
>>>
>>> We have defined a set of backend REST APIs which works on our
>>> model (list/create/delete/update). The web application front end
>>> is the primary consumer of this REST API. The web application and
>>> RESTful resources are deployed into Jersey as a WAR.
>>> In addition to performing CRUD operations, the web application
>>> also operates on each model (for ex: if the model is secure, it
>>> can perform login/logout on the model). The users can select the
>>> model they wish to operate and the model will be set in session
>>> for that user until they decide to choose a different model to
>>> work with. At application startup, we need to select a default
>>> model and set it in session so that the user can use this default
>>> model at first access. This is where my requirement comes into
>>> picture. When I start my resources, I need to somehow set the
>>> default model in session if there is one so that the user is
>>> presented with this default model.
>>>
>>> So, I try to set this in the constructor by injecting a HTTP
>>> servlet request and fetch the session from the request as shown
>>> below which seems to be an illegal scenario.
>>>
>>> @Singleton
>>> public static class ModelResource {
>>> @Context
>>> HttpServletRequest r;
>>>
>>> public ModelResource(@Context HttpServletRequest req) {
>>> req.getSession().setAttribute("currentmodel", "defaultmodel");
>>> }
>>>
>>> @Produces("text/plain")
>>> @GET
>>> public String get() {
>>> return (String) r.getAttribute("currentmodel");
>>> }
>>> }
>>>
>>> I appreciate your inputs.
>>>
>>> -Arul
>>>
>>> Paul Sandoz wrote:
>>>> Hi Arul,
>>>>
>>>> I realized there is something wrong with the way you are doing
>>>> things in that you assume a singleton instance is associated
>>>> with a session. This will not be the case for multiple clients,
>>>> thus your service is likely to fail in that case.
>>>>
>>>> So... i have given up resisting providing life-cycle support for
>>>> HTTP servlet sessions, and have implemented such support with a
>>>> new annotation:
>>>>
>>>> com.sun.jersey.spi.container.servlet.PerSession
>>>>
>>>> And you can use it like this:
>>>>
>>>> @Path("resource")
>>>> @PerSession
>>>> public class Resource {
>>>> int i = 0;
>>>>
>>>> @GET
>>>> public String get() {
>>>> i++;
>>>> return "" + i;
>>>> }
>>>> }
>>>>
>>>> Instances are stored as attributes on the session using the
>>>> class name as the key. It requires that you are using a servlet
>>>> as the HTTP container.
>>>>
>>>> Use it wisely with the knowledge that you are breaking an
>>>> important RESTful constraint [1].
>>>>
>>>> Paul.
>>>>
>>>> [1] http://www.crummy.com/2008/08/19/2
>>>>
>>>> Arul Dhesiaseelan wrote:
>>>>> Hi Paul,
>>>>>
>>>>> I am still having issue with constructor injection in singleton
>>>>> resources in Jersey 0.9. If I comment
>>>>> SingletonConstructorResource in the below code, I can run other
>>>>> 3 scenarios just fine which was working fine in 0.8 too. If I
>>>>> uncomment SingletonConstructorResource, then none of the
>>>>> scenarios work in 0.9. Am I missing something? I remember you
>>>>> had fixed this issue earlier.
>>>>>
>>>>> I am getting the following exception when trying to invoke any
>>>>> of the resources:
>>>>>
>>>>> com.sun.jersey.api.container.ContainerException: Unable to
>>>>> create resource
>>>>> at com.sun.jersey.impl.resource.SingletonProvider.init
>>>>> (SingletonProvider.java:88)
>>>>> at
>>>>> com.sun.jersey.spi.resource.ResourceProviderFactory.createProvider
>>>>> (ResourceProviderFactory.java:132)
>>>>> at com.sun.jersey.impl.model.ResourceClass.init
>>>>> (ResourceClass.java:180)
>>>>> at
>>>>> com.sun.jersey.impl.application.WebApplicationImpl.getResourceClas
>>>>> s(WebApplicationImpl.java:267)
>>>>> at
>>>>> com.sun.jersey.impl.application.WebApplicationImpl.processRootReso
>>>>> urces(WebApplicationImpl.java:796)
>>>>> at
>>>>> com.sun.jersey.impl.application.WebApplicationImpl.initiate
>>>>> (WebApplicationImpl.java:668)
>>>>> at
>>>>> com.sun.jersey.impl.application.WebApplicationImpl.initiate
>>>>> (WebApplicationImpl.java:485)
>>>>> at
>>>>> com.sun.jersey.spi.container.servlet.ServletContainer.initiate
>>>>> (ServletContainer.java:559)
>>>>> at
>>>>> com.sun.jersey.spi.container.servlet.ServletContainer.load
>>>>> (ServletContainer.java:483)
>>>>> at
>>>>> com.sun.jersey.spi.container.servlet.ServletContainer.init
>>>>> (ServletContainer.java:165)
>>>>> at org.mortbay.jetty.servlet.ServletHolder.initServlet
>>>>> (ServletHolder.java:433)
>>>>> at org.mortbay.jetty.servlet.ServletHolder.getServlet
>>>>> (ServletHolder.java:342)
>>>>> at org.mortbay.jetty.servlet.ServletHolder.handle
>>>>> (ServletHolder.java:463)
>>>>> at org.mortbay.jetty.servlet.ServletHandler.handle
>>>>> (ServletHandler.java:362)
>>>>> at org.mortbay.jetty.servlet.SessionHandler.handle
>>>>> (SessionHandler.java:181)
>>>>> at org.mortbay.jetty.handler.ContextHandler.handle
>>>>> (ContextHandler.java:729)
>>>>> at org.mortbay.jetty.handler.HandlerWrapper.handle
>>>>> (HandlerWrapper.java:152)
>>>>> at org.mortbay.jetty.Server.handle(Server.java:324)
>>>>> at org.mortbay.jetty.HttpConnection.handleRequest
>>>>> (HttpConnection.java:505)
>>>>> at org.mortbay.jetty.HttpConnection
>>>>> $RequestHandler.headerComplete(HttpConnection.java:829)
>>>>> at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:513)
>>>>> at org.mortbay.jetty.HttpParser.parseAvailable
>>>>> (HttpParser.java:211)
>>>>> at org.mortbay.jetty.HttpConnection.handle
>>>>> (HttpConnection.java:380)
>>>>> at org.mortbay.jetty.bio.SocketConnector$Connection.run
>>>>> (SocketConnector.java:228)
>>>>> at org.mortbay.thread.QueuedThreadPool$PoolThread.run
>>>>> (QueuedThreadPool.java:488)
>>>>> Caused by: java.lang.reflect.InvocationTargetException
>>>>> at sun.reflect.NativeConstructorAccessorImpl.newInstance0
>>>>> (Native Method)
>>>>> at sun.reflect.NativeConstructorAccessorImpl.newInstance
>>>>> (NativeConstructorAccessorImpl.java:39)
>>>>> at sun.reflect.DelegatingConstructorAccessorImpl.newInstance
>>>>> (DelegatingConstructorAccessorImpl.java:27)
>>>>> at java.lang.reflect.Constructor.newInstance
>>>>> (Constructor.java:494)
>>>>> at com.sun.jersey.impl.application.WebApplicationImpl
>>>>> $DefaultResourceComponentProvider.getInstance
>>>>> (WebApplicationImpl.java:465)
>>>>> at com.sun.jersey.impl.resource.SingletonProvider.init
>>>>> (SingletonProvider.java:84)
>>>>> ... 24 more
>>>>> Caused by: java.lang.NullPointerException
>>>>> at jersey.Inject$SingletonConstructorResource.(Inject.java:42)
>>>>> ... 30 more
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> public class Inject {
>>>>> @Path("singleton")
>>>>> @Singleton
>>>>> public static class SingletonResource {
>>>>> @Context
>>>>> HttpServletRequest r;
>>>>>
>>>>> @Produces("text/plain")
>>>>> @GET
>>>>> public String get() {
>>>>> return r.getPathInfo();
>>>>> }
>>>>> }
>>>>>
>>>>> // @Path("singleton/constructor")
>>>>> // @Singleton
>>>>> // public static class SingletonConstructorResource {
>>>>> // @Context HttpServletRequest r;
>>>>> //
>>>>> // public SingletonConstructorResource(@Context
>>>>> HttpServletRequest r) {
>>>>> // this.r = r;
>>>>> // r.getSession().setAttribute("test", "true");
>>>>> // }
>>>>> //
>>>>> // @Produces("text/plain")
>>>>> // @GET public String get() {
>>>>> // return (String)r.getAttribute("test");
>>>>> // }
>>>>> // }
>>>>>
>>>>> @Path("perrequest")
>>>>> public static class PerRequestResource {
>>>>> @Context
>>>>> HttpServletRequest r;
>>>>>
>>>>> @Produces("text/plain")
>>>>> @GET
>>>>> public String get() {
>>>>> return r.getPathInfo();
>>>>> }
>>>>> }
>>>>>
>>>>> @Path("perrequest/constructor")
>>>>> public static class PerRequestConstructorResource {
>>>>> String path;
>>>>>
>>>>> public PerRequestConstructorResource(@Context
>>>>> HttpServletRequest r) {
>>>>> path = r.getPathInfo();
>>>>> }
>>>>>
>>>>> @Produces("text/plain")
>>>>> @GET
>>>>> public String get() {
>>>>> return path;
>>>>> }
>>>>> }
>>>>>
>>>>> public static void main(String[] args) throws Exception {
>>>>> ServletHolder sh = new ServletHolder(ServletContainer.class);
>>>>> sh.setInitParameter
>>>>> ("com.sun.jersey.config.property.packages", "jersey");
>>>>> Server server = new Server(9999);
>>>>> org.mortbay.jetty.servlet.Context context = new
>>>>> org.mortbay.jetty.servlet.Context(server, "/",
>>>>> org.mortbay.jetty.servlet.Context.SESSIONS);
>>>>> context.addServlet(sh, "/*");
>>>>> server.start();
>>>>> }
>>>>>
>>>>> }
>>>>>
>>>>> Thanks!
>>>>> Arul
>>>>>
>>>>>
>>>>> ------------------------------------------------------------------
>>>>> ---
>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>>
>>>>
>>>
>>>
>>> --------------------------------------------------------------------
>>> -
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>>
>> ________________________________
>> Scanned by MessageLabs for Flux
>> ________________________________
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>