geronimo-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Quintin Beukes <quin...@skywalk.co.za>
Subject Re: Stateful session bean has no state
Date Tue, 13 Oct 2009 11:43:29 GMT
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

Mime
View raw message