5/06/2010

Example of EJB 3.1 Stateful Session Bean and Servlet

Stateful session bean class:

package test;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Stateful;
import javax.ejb.StatefulTimeout;

@Stateful
@StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)
public class StatefulTestBean {
private static final Logger logger = Logger.getLogger("test");

private String clientInfo;

@SuppressWarnings("unused")
@PrePassivate
private void prePassivate() {
logger.info("In PrePassivate method");
}

@SuppressWarnings("unused")
@PostActivate
private void postActivate() {
logger.info("In PostActivate method");
}

public String getBeanInfo() {
return this.toString();
}

public String getClientInfo() {
return clientInfo;
}

public void setClientInfo(String clientInfo) {
this.clientInfo = clientInfo;
}
}
Servlet class:
package test;
import java.io.IOException;
import java.io.PrintWriter;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet(urlPatterns = "/TestServlet")
public class TestServlet extends HttpServlet {
private static final String STATEFUL_TEST_BEAN_KEY = "STATEFUL_TEST_BEAN_KEY";

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter writer = response.getWriter();
StatefulTestBean statefulTestBean = getStatefulTestBean(request);
writer.println("clientInfo: " + statefulTestBean.getClientInfo());
writer.println("beanInfo: " + statefulTestBean.getBeanInfo());
}

private StatefulTestBean getStatefulTestBean(HttpServletRequest request)
throws ServletException {
HttpSession httpSession = request.getSession(true);
StatefulTestBean statefulTestBean = (StatefulTestBean)
httpSession.getAttribute(STATEFUL_TEST_BEAN_KEY);
if (statefulTestBean == null) {
try {
InitialContext ic = new InitialContext();
statefulTestBean = (StatefulTestBean) ic.lookup("java:module/StatefulTestBean");
httpSession.setAttribute(STATEFUL_TEST_BEAN_KEY, statefulTestBean);

String userAgent = request.getHeader("User-Agent");
String userName = request.getParameter("userName");
statefulTestBean.setClientInfo(userAgent + ", " + userName);
} catch (NamingException e) {
throw new ServletException(e);
}
}
return statefulTestBean;
}
}
To compile the above 2 classes:
javac -cp "$GLASSFISH_HOME/modules/*" TestServlet.java StatefulTestBean.java
Copy *.class files under a WEB-INF directory, and package the above 2 classes into a WAR file, stateful.war, that contains the following:
WEB-INF/classes/test/StatefulTestBean.class
WEB-INF/classes/test/TestServlet.class
To deploy it, copy stateful.war to appserver autodeploy directory.

I did the following to test the stateful session behavior:

1, open the following url in firefox:
http://localhost:8080/stateful/TestServlet?userName=nobody

will get the following response:
clientInfo: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3, nobody
beanInfo: test._StatefulTestBean_Serializable@3af78ba5

2, In the same firefox window, enter url without userName:
http://localhost:8080/stateful/TestServlet

will still get the same response, since the second request share the same http session and stateful session bean with the first request.

3, Open a new firefox window and repeat step 2, will still get the same response, since the http session is tied to the firefox browser.

4, Open a chrome window and repeat step 2, will get a different response due to a new http session and new stateful session bean instance were created.

Since both http sessin and stateful session bean are used to manage user session, their timeout value should be in kept in sync.

This app is programmed to JavaEE 6 and EJB 3.1, using some new features such as @StatefulTimeout and a portable module-scope jndi name. I've tested with GlassFish 3.0, and it should also work, without any modification, in any JavaEE-6-compliant appserver. To run with JavaEE 5 appserver, some minor modifications are needed.

The stateful bean reference is looked up, instead of using field injection. This is necessary to keep it thread safe and avoid being accessed by different users.

15 comments:

alan thomshon said...

Weboutsourcing team offer best affordable web designing services in India. Improve your website look and feel with our web 2.0 oriented web designing services.

Daniel Hansen said...

"To run with JavaEE 5 appserver, some minor modifications are needed"

Is there a somewhere that these mods are posted?

Daniel Hansen
Webmaster, GroupReign.Org
One24

javahowto said...

To run with Java EE 5 appserver, you will need to remove the line:

@StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)

and also replace @WebServlet annotation with servlet declaration and url mapping in web.xml.

@StatefulTimeout and @WebServlet are new in Java EE 6 (EJB 3.1 and Servlet 3.0, respectively).

Daniel Hansen said...

You were right. That was minor..thanks!

irenew bracelet said...

"To run with Java EE 5 appserver, you will need to remove the line:

@StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)"

Thank you. I had totally missed that after about two hours of looking through bugs.

` Corey

Anonymous said...

Thanks for that short tutorial. I am newbie to java ee, it helped me a lot.

Corey said...

"Thanks for that short tutorial. I am newbie to java ee, it helped me a lot."

I've found some really good online resources for this. Let me see if I can find them and I'll repost them.

Corey - Latest Blog Post Batman Legos

Nils said...

Hello javahowto,

thx alot.

I am wondering how the session tracking is implemented in your solution.
I.e. how does the client save the session identifiers (SessionID)?
Are cookies required?

BR
Nils

Nils said...

Hello javahowto,

thx alot.

I am wondering how the session tracking is implemented in your solution.
I.e. how does the client save the session identifiers (SessionID)?
Are cookies required?

BR
Nils

javahowto said...

Browsers typically need to allow cookies for session tracking. The session tracking details are all handled by the underlying appserver or web container. Apps use the session tracking service by calling api like HttpServletRequest.getSession(), and store any stateful ejb reference into the http session.

Anonymous said...

As you have given example of using http session for stateful bean, similiarly we can store stateless bean and I will get the same instance. then how these two bean are different?

javahowto said...

stateless bean instances are all considered the same, so no need to save it in http session. You can use the stateless ejb injected whenever you need it, or look it up.

Nancy Darnard said...

With Java is there 16 ways to accomplish the same thing like c# looks like it is?

Ecommerce Website Development said...

I have just started learning it and i found this language will be not too tough like Php and it is my favorite language.

Anonymous said...

@Ecommerce Website Development

PHP seems easier than this :-)