Paul,
Thanks for your inputs.
I will use the PerSession annotation as per your suggestion. Is it
available as part of .10 snapshots?
-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.getResourceClass(WebApplicationImpl.java:267)
>>>>
>>>> at
>>>> com.sun.jersey.impl.application.WebApplicationImpl.processRootResources(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
> ________________________________