Apache Geronimo > Discussion Forums  User List | Dev List | Wiki | Issue Tracker  

Stateful session bean has no state

View: New views
9 Messages — Rating Filter:   Alert me  

Stateful session bean has no state

by Antonio Fornié () :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello again!

I made a stateful sessiob bean and it's working the same way my stateless beans do: they forget their state. Here's my code:

@Stateful
public class CartBean implements CartLocal {
       
        private Integer number = new Integer(0);
       
        public void setNumber(Integer number) {
                this.number = number;
        }

        public Integer getNumber() {
                return this.number;
        }

        @Override
        public Integer getNumberService() {
                this.number += 10;
                return this.number;
        }
       
}

My jsp uses CartLocal interface wich only shows "getNumberService()" method. When requesting the jsp with my web browser it always shows ten. when refreshing the page it should show 20, but once again shows 10. What am I doing wrong?

Thank you very much!

Re: Stateful session bean has no state

by Quintin Beukes-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Are you storing your session bean instance in the servlet/JSP session context?

Quintin Beukes



On Mon, Oct 12, 2009 at 8:48 PM, Antonio Fornié
<sitaronocturnal@...> wrote:

>
> Hello again!
>
> I made a stateful sessiob bean and it's working the same way my stateless
> beans do: they forget their state. Here's my code:
>
> @Stateful
> public class CartBean implements CartLocal {
>
>        private Integer number = new Integer(0);
>
>        public void setNumber(Integer number) {
>                this.number = number;
>        }
>
>        public Integer getNumber() {
>                return this.number;
>        }
>
>        @Override
>        public Integer getNumberService() {
>                this.number += 10;
>                return this.productNumber;
>        }
>
> }
>
> My jsp uses CartLocal interface wich only shows "getNumberService()" method.
> When requesting the jsp with my web browser it always shows ten. when
> refreshing the page it should show 20, but once again shows 10. What am I
> doing wrong?
>
> Thank you very much!
> --
> View this message in context: http://www.nabble.com/Stateful-session-bean-has-no-state-tp25861132s134p25861132.html
> Sent from the Apache Geronimo - Users mailing list archive at Nabble.com.
>
>

Re: Stateful session bean has no state

by Quintin Beukes-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Just to clarify.

An EJB is referenced through a "proxy". When you get the instance to
the session bean, you actually obtain a reference to a proxy class
which implements the EJB's business interface (the one annotated with
@Local or @Remote). So any methods you invoke are done so on the
proxy, and the proxy does the work of communicating with the actual
EJB instance.

So, with a Stateless bean, every invocation on the obtained instance
(ie. the proxy), can happen on a different physical instance. So it's
at the whim of the implementation/provider, and therefore you can
never rely on any member values being the same in between method
calls. Literally, this code could work with 2 separate physical
instances, or it could work with one - you can never be sure - it's a
stateless EJB.
public void someEjbInvocation();
{
  MyStatelessEjbLocal myEjb = initialContext.lookup("MyStatelessEjbLocal");
  myEjb.callMethod1();
  myEjb.callMethod2();
}

With a Stateful bean, when you get a reference via the InitialContext
or injection, it will still be via a proxy as above, but this time it
will always be to the same physical bean instance. So any method
invocations like in the example above will be guaranteed to happen on
the same object instance, and therefore you can store values in it's
member fields and know that it will be there next time. Everytime you
do a lookup to the Stateful bean via the InitialContext, you will get
a reference to a proxy pointing to a new/fresh EJB instance of that
bean. So the following will be 2 separate instances of the same
stateful EJB:
public void someEjbInvocation();
{
  MyStatefulEjbLocal myEjbInstance1 =
initialContext.lookup("MyStatefulEjbLocal");
  myEjbInstance1.callMethod1();

  MyStatefulEjbLocal myEjbInstance2 =
initialContext.lookup("MyStatefulEjbLocal");
  myEjbInstance2.callMethod1();
}

So if you want to do your invocations on the same instance, ie. keep
the state, you need to be sure that you keep the reference somewhere,
like in the session object (HttpSession) of the servlet/JSP. Otherwise
you will keep getting a new instance and you're state won't be saved.

Just a tip: Further, when you're done with the session bean (like when
the client logs out), call it's remove method (any empty method on the
bean annotated with @javax.ejb.Remove - it must be exposed via the
interfaces as well). This will cause the bean to be garbage collected.
The alternative is to have it timeout, but in a very busy system with
long timeouts this could potentially waste a lot of resources.

I hope this solves your problem.

Quintin Beukes



On Mon, Oct 12, 2009 at 9:50 PM, Quintin Beukes <quintin@...> wrote:

> Are you storing your session bean instance in the servlet/JSP session context?
>
> Quintin Beukes
>
>
>
> On Mon, Oct 12, 2009 at 8:48 PM, Antonio Fornié
> <sitaronocturnal@...> wrote:
>>
>> Hello again!
>>
>> I made a stateful sessiob bean and it's working the same way my stateless
>> beans do: they forget their state. Here's my code:
>>
>> @Stateful
>> public class CartBean implements CartLocal {
>>
>>        private Integer number = new Integer(0);
>>
>>        public void setNumber(Integer number) {
>>                this.number = number;
>>        }
>>
>>        public Integer getNumber() {
>>                return this.number;
>>        }
>>
>>        @Override
>>        public Integer getNumberService() {
>>                this.number += 10;
>>                return this.productNumber;
>>        }
>>
>> }
>>
>> My jsp uses CartLocal interface wich only shows "getNumberService()" method.
>> When requesting the jsp with my web browser it always shows ten. when
>> refreshing the page it should show 20, but once again shows 10. What am I
>> doing wrong?
>>
>> Thank you very much!
>> --
>> View this message in context: http://www.nabble.com/Stateful-session-bean-has-no-state-tp25861132s134p25861132.html
>> Sent from the Apache Geronimo - Users mailing list archive at Nabble.com.
>>
>>
>

Re: Stateful session bean has no state

by Antonio Fornié () :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thank you once again. Now it has state, the problem now is that it has the same state for everybody. I used two browsers at a time, a Firefox and an IE. They both had the same state, if I refreshed one of them then the number had been incremented for the other one. By the way, I used @EJB annotations to have my SFSB injected in my servlet (in case it helps).

Just in case you were about to reply that I have to look for my SFSB in my session and if there's no SFSB there I have to look up via JNDI and store it in session, well, it seems I will have to do all the work to keep an object (the SFSB) per session, so... what's the use of Stateful Session Beans? If I will have to do all the work by myself, I can create an object (not a EJB, but a simple POJO) and avoid using complicated EJBs. I mean, I though container was responsible of assigning a SFSB to each session.

Of course, if the only advantage was to have an object (the implementation) knowing only the interface, I can use a Factory Method Pattern or many other solutions.

Please, don't see me as an EJB detractor, I'm only asking because I really liked the fact that using Stateful Session Beans I could forget about managing objects in session as the container was doing that work for me. I only want to know. In fact I'm sure it won't be necessary to do all that job, and it suffices to have a servlet property annotated, but if so why my two browsers got the same SFSB?

Thank you very much.

Re: Stateful session bean has no state

by Quintin Beukes-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

No problem. Your question and intentions are completely valid.

See my answers below.

> Thank you once again. Now it has state, the problem now is that it has the
> same state for everybody. I used two browsers at a time, a Firefox and an
> IE. They both had the same state, if I refreshed one of them then the number
> had been incremented for the other one. By the way, I used @EJB annotations
> to have my SFSB injected in my servlet (in case it helps).

Most servlet containers only have one instance of the servlet. So when
you inject via the @EJB annotation, all clients will receive the exact
same instance, because only one injection is made when the servlet
class is instantiated. In general, remember this, you should not store
ANY client specific data as member fields in the servlet, because
those fields will be shared by the client. If you need client specific
data, store it in a separate object attached to one of the servlet
contexts unique to the client (request/session).

Some servlet containers create more than one instance of the servlet
class, but still a single instance may be shared, so never keep any
type of state other than page/application state as fields in the
servlet class.

> Just in case you were about to reply that I have to look for my SFSB in my
> session and if there's no SFSB there I have to look up via JNDI, right?
> Well, however, it seems I will have to do all the work to keep an object
> (the SFSB) per session, so... what's the use of Stateful Session Beans? If I
> will have to do all the work by myself, I can create an object (not a EJB,
> but a simple POJO) and avoid using complicated EJBs. I mean, I though
> container was responsible of assigning a SFSB to each session.

Unfortunately a lookup via JNDI is the case if you want client
specific instances. I recommend doing something like a simple facade:
private MyStatefulEjbLocal getEjb(HttpSession session)
{
  MyStatefulEjbLocal ejb =session.getAttribute("MyStatefulEjb");
  if (ejb == null)
  {
     ejb = new InitialContext().lookup("MyStatefulEjbLocal");
     session.setAttribute("MyStatefulEjb", ejb);
  }
  return ejb;
}

Then you can retrieve the EJB at anytime using getEjb(), only passing
in the session (or another object from which the session can be
retrieved).

And sure, you can use a simple POJO as well. The reason for using EJBs
are more than ease of use. In fact, the first 2 EJBs specs were
anything but easy. You use EJBs to wrap code in container managed
transactions, or more easily run it on clusters or remote servers -
enterprise stuff. If you merely want to keep state throughout a
session and don't care for these EJB specific features, then a POJO
might be a much better option, and much more light weight. Though
using EJBs you do have the potential flexibility and power of EJBs at
your disposal.

> Please, don't see me as an EJB detractor, I'm only asking because I really
> liked the fact that using Stateful Session Beans I could forget about
> managing objects in session as the container was doing that work for me. I
> only want to know.

Not at all, it's good to want to know. I do hope this clears things up
for you. Sorry about that.

Here is something you could try. Create a class called
"MyApplication". From now on, this will be where you're actual logic
takes place - and the servlet will delegate requests to it.
So, your doGet() or doPost() method changes to this:
public void doGet(....)
{
  HttpSession session = request.getSession();
  MyApplication app = session.getAttribute("MyApplication");
  if (app == null)
  {
    app = new MyApplication();
    new InitialContent().bind("inject", app);
  }
  app.handleCartRequest(request, response);
}

And your MyApplication class will be:
@LocalClient
public class MyApplication
{
  @EJB MyStatefulCartEjb cart;

  public void handleCartRequest(HttpSerlvetRequest request,
HttpServletResponse response)
  {
    // move your cart handling logic here
  }
}

Then remember to add an ejb-jar.xml (with contents = "<ejb-jar/>") to
your war's META-INF directory as well (for the @LocalClient to work).

Obviously it doesn't need to be exactly like this. The important thing
is to have a separate class with your @EJB annotations, which itself
needs to be annotated @LocalClient and the ejb-jar.xml in the WAR's
META-INF directory. Then the initialContext.bind("inject", obj) call
will cause the injections to happen. You can read more about it over
here: http://openejb.apache.org/3.0/local-client-injection.html

So the above gives a unique instance to every client, which itself is
stored in the session and retrieved with every request. So all your
servlets would have such code in their doPost/doGet methods, and all
of them work on a session object instance.

Q

Re: Stateful session bean has no state

by Quintin Beukes-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hey,

I made a mistake in the example code - I forgot to update the session,
please replace into it the following method:
public void doGet(....)
{
 HttpSession session = request.getSession();
 MyApplication app = session.getAttribute("MyApplication");
 if (app == null)
 {
   app = new MyApplication();
   new InitialContent().bind("inject", app);
   session.setAttribute("MyApplication", app);
 }
 app.handleCartRequest(request, response);
}

Quintin Beukes



On Tue, Oct 13, 2009 at 1:43 PM, Quintin Beukes <quintin@...> wrote:

> No problem. Your question and intentions are completely valid.
>
> See my answers below.
>
>> Thank you once again. Now it has state, the problem now is that it has the
>> same state for everybody. I used two browsers at a time, a Firefox and an
>> IE. They both had the same state, if I refreshed one of them then the number
>> had been incremented for the other one. By the way, I used @EJB annotations
>> to have my SFSB injected in my servlet (in case it helps).
>
> Most servlet containers only have one instance of the servlet. So when
> you inject via the @EJB annotation, all clients will receive the exact
> same instance, because only one injection is made when the servlet
> class is instantiated. In general, remember this, you should not store
> ANY client specific data as member fields in the servlet, because
> those fields will be shared by the client. If you need client specific
> data, store it in a separate object attached to one of the servlet
> contexts unique to the client (request/session).
>
> Some servlet containers create more than one instance of the servlet
> class, but still a single instance may be shared, so never keep any
> type of state other than page/application state as fields in the
> servlet class.
>
>> Just in case you were about to reply that I have to look for my SFSB in my
>> session and if there's no SFSB there I have to look up via JNDI, right?
>> Well, however, it seems I will have to do all the work to keep an object
>> (the SFSB) per session, so... what's the use of Stateful Session Beans? If I
>> will have to do all the work by myself, I can create an object (not a EJB,
>> but a simple POJO) and avoid using complicated EJBs. I mean, I though
>> container was responsible of assigning a SFSB to each session.
>
> Unfortunately a lookup via JNDI is the case if you want client
> specific instances. I recommend doing something like a simple facade:
> private MyStatefulEjbLocal getEjb(HttpSession session)
> {
>  MyStatefulEjbLocal ejb =session.getAttribute("MyStatefulEjb");
>  if (ejb == null)
>  {
>     ejb = new InitialContext().lookup("MyStatefulEjbLocal");
>     session.setAttribute("MyStatefulEjb", ejb);
>  }
>  return ejb;
> }
>
> Then you can retrieve the EJB at anytime using getEjb(), only passing
> in the session (or another object from which the session can be
> retrieved).
>
> And sure, you can use a simple POJO as well. The reason for using EJBs
> are more than ease of use. In fact, the first 2 EJBs specs were
> anything but easy. You use EJBs to wrap code in container managed
> transactions, or more easily run it on clusters or remote servers -
> enterprise stuff. If you merely want to keep state throughout a
> session and don't care for these EJB specific features, then a POJO
> might be a much better option, and much more light weight. Though
> using EJBs you do have the potential flexibility and power of EJBs at
> your disposal.
>
>> Please, don't see me as an EJB detractor, I'm only asking because I really
>> liked the fact that using Stateful Session Beans I could forget about
>> managing objects in session as the container was doing that work for me. I
>> only want to know.
>
> Not at all, it's good to want to know. I do hope this clears things up
> for you. Sorry about that.
>
> Here is something you could try. Create a class called
> "MyApplication". From now on, this will be where you're actual logic
> takes place - and the servlet will delegate requests to it.
> So, your doGet() or doPost() method changes to this:
> public void doGet(....)
> {
>  HttpSession session = request.getSession();
>  MyApplication app = session.getAttribute("MyApplication");
>  if (app == null)
>  {
>    app = new MyApplication();
>    new InitialContent().bind("inject", app);
>  }
>  app.handleCartRequest(request, response);
> }
>
> And your MyApplication class will be:
> @LocalClient
> public class MyApplication
> {
>  @EJB MyStatefulCartEjb cart;
>
>  public void handleCartRequest(HttpSerlvetRequest request,
> HttpServletResponse response)
>  {
>    // move your cart handling logic here
>  }
> }
>
> Then remember to add an ejb-jar.xml (with contents = "<ejb-jar/>") to
> your war's META-INF directory as well (for the @LocalClient to work).
>
> Obviously it doesn't need to be exactly like this. The important thing
> is to have a separate class with your @EJB annotations, which itself
> needs to be annotated @LocalClient and the ejb-jar.xml in the WAR's
> META-INF directory. Then the initialContext.bind("inject", obj) call
> will cause the injections to happen. You can read more about it over
> here: http://openejb.apache.org/3.0/local-client-injection.html
>
> So the above gives a unique instance to every client, which itself is
> stored in the session and retrieved with every request. So all your
> servlets would have such code in their doPost/doGet methods, and all
> of them work on a session object instance.
>
> Q
>

Re: Stateful session bean has no state

by Antonio Fornié :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Yes, each Servlet it's created only once. I think that's true for ALL Servlet Containers, in fact is part of the specs, that's why so much has been written about about thread safe Servlets, against and in favor (do you remember there was a time when everybody tried to use thread safe servlets, and some years later everybody forgot about it just to remove critical code from the servlets in order not to lose performance?).

I though that it could be like you say, having to manage myself the one-EFSB-per-session matters, but I didn't want to believe. I knew that using EJB had those benefits (transactional, distributed...) and that EJB prior to version 3.0 was rather complex (I've read the famous Rod Johnson book about development without EJB) and that's why I've been working with Spring for years... Now that I was trying to get involved in EJB 3 I find that EJB 3.0 is much better, but in the case of Stateful Beans it's been a surprise: I don't understand why to use the @EJB annotation for a SFSB. It's only valid for the first user session, right?

I though that being EJB 3 a response to Spring, managing objects per session would be a little easier.

Anyway I will use your recommendation and have a class to make sure I always have one and only one SFSB per session. I didn't know about @LocalClient annotation.

Thank you very much for your detailed answer. By the way, and only to learn, what would you answer to people who think EJB 3 is still far more complex than other alternatives.

Thank you very much!

Re: Stateful session bean has no state

by Quintin Beukes-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> Thank you very much for your detailed answer. By the way, and only to learn,
> what would you answer to people who think EJB 3 is still far more complex
> than other alternatives.

To tell you the truth, I wouldn't know what to say. The only other
alternative I know of is Spring, and it's a completely different
approach.Re. complexity I would say Spring is more complex. With
flexibility I would say Spring is far more flexible. But more than
this the person stating it's more complex needs to be more specific,
because I can't see how it's complex at all.

> Thank you very much!

Glad to be of service.

Re: Stateful session bean has no state

by kevan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Oct 13, 2009, at 11:40 AM, Antonio Fornié wrote:

>
> Thank you very much!

+1. Thanks Quintin!

--kevan