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.

Followers

Pageviews Last 7 Days