10
votes

I am trying my first EJBs with Glassfish Server ( A simple shopping cart). I intended to use the CartBean for each Http Session. If my Cart Bean is following-

public interface CartLocal {
 public void addItem(String item);
 public void removeItem(String item);
}

@Stateful
public class CartBean implements CartLocal {
 List<String> item = new java.util.ArrayList<String>();
 public void addItem(String item) {
  ....
 }
 public void removeItem(String item) {
  ....
 }
}

I have to use the above stateful session bean in a web servlet client such that, for each new Http Session, we get a new stateful session bean. So that there is one shopping cart for one user. Is my understanding wrong of using session beans in servlet or the below code is wrong, this creates one stateful session bean for all the users.

@EJB CartLocal cart;

protected void doGet(....) throws IOException...... {
 cart.addItem(....);
}
2

2 Answers

18
votes

The http servlet is shared by all clients of that servlet so injecting it with a stateful session bean is not correct and will cause undesirable effects. Session beans are meant to be used per client and they are typically stored in http session so that all requests for that session can have access to session bean. You will have to use jndi lookup inside the doGet method and store that reference in http session. Once stored you would need to retrieve from http session and use that.

More Info

You are getting it a bit wrong. Stateful session bean class represents how you model your stateful data which could be a graph of fine grained related classes. You ask for a statful bean from the container (which creates/manages/activates/passivates it).These services are what we use Stateful session bean for. However container has no knowledge that whatever object it is handing over belongs to which client. So then the http session comes into picture. This part is what is not emphasised as much as it should be hence your confusion. Http Session is a perfect storage place where all request from same web client have access to all attributes stored in http session. So you ask for it from the container and keep it in a place (http session) from where it can be referred again by all requests for same session. Now imagine the case of non-web clients. There you do not have http session or similar mechanism. You will have to create a storage mechanism of your own to identify different client with their respective stateful beans.A possible way could be possibly storing the stateful bean reference somewhere ( say in a map with key as clientId and value as bean reference), and the next time client wants to access the bean it passes the clientId and gets it from the map.

As far as preference for http session over stateful bean is concerned, it important to understand that http session is not thread safe. So in case you have an ajax heavy application accessing an object in session simultaneously you will have to provide your own synchronization mechanism which will not be scalable and will impact performance heavily. In case of stateful session beans the container manages the synchronization.

Here is an interesting discussion on the topic of using http session for storing state. The discussion is on Brian Goetz's very informative article "Are All Stateful Java Web Applications Broken?". Unfortunately I cannot locate the original article on IBM site but the discussion thread gives enough material to ponder.

4
votes

You of course can use stateful bean but you just can't inject it because single servlet instance by default can be shared to serve multiple requests concurrently which means your code is not thread-safe. But you can always perform JNDI lookup in your doGet method for instance

CartBean bean = (CartBean) new InitialContext().lookup(jndiName);

See some tutorial for making lookups here.