Proving Stateful Session Beans activation and passivation mechanism
I’ve never worked with stateful session beans in the real world. However, as I’m preparing to take the EJB 3.1 developer certification I’m playing with activation and passivation to prove the concepts and see how it works in practice.
To prove the behavior I decided to brute force the passivation creating a huge number of stateful beans from a single class which implements the callback methods for activation and passivation.
First, I’ve created the following stateful session bean:
package br.com.amadei.ejb;
//imports
@Stateful
public class MyStatefulSessionBean {
public String sayHello() {
return "Hello, world: " + new Date();
}
@PrePassivate
public void prepareForPassivation() {
System.out.println("Will passivate: " + this);
}
@PostActivate
public void executeAfterActivation() {
System.out.println("After activate: " + this);
}
@PreDestroy
public void destroyed() {
System.out.println("Destroyed: " + this);
}
}
As you may see, the bean class defines callback methods to be invoked when the bean is passivated or activated. But how can I ask the application server to passivate the bean? You can’t but, in case of Glassfish, you can either configure the cache of the EJB container or override the EJB container settings for your EJB and configure special settings for the cache of a specific EJB. For the latter option, you have to configure the file sun-ejb-jar.xml as the following sample:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-ejb-jar PUBLIC ... >
<sun-ejb-jar>
<enterprise-beans>
<ejb>
<ejb-name>MyStatefulSessionBean</ejb-name>
<bean-cache>
<max-cache-size>200</max-cache-size>
</bean-cache>
</ejb>
</enterprise-beans>
</sun-ejb-jar>
If it’s a web application (as allowed in Java EE 6), you can place sun-ejb-jar.xml inside WEB-INF.
After that, we need a way to create all these beans. In a real world app they would be created by real users, probably one by one but in our case we will force the creation using a JSP file similar to this one:
<%@page import="br.com.amadei.ejb.MyStatefulSessionBean"%>
<%@page import="javax.naming.InitialContext"%>
<%@page import="javax.naming.Context"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<%
Context context = new InitialContext();
int loopCount = Integer.parseInt(request.getParameter("loopCount"));
for(int i=1; i<=loopCount; i++) {
MyStatefulSessionBean bean =
(MyStatefulSessionBean)context.lookup(
"java:module/MyStatefulSessionBean");
session.setAttribute(String.valueOf(i), bean);
%>
<p>
<a href="activate.jsp?id=<%=i%>">Click to Activate Bean <%=i%></a>
</p>
<%
}
%>
</body>
</html>
Invoking this JSP page with the parameter ?loopCount=50 does not passivate anything, but try it with ?loopCount=200, for example, and you will see lines like the following one printed to the console:
INFO: Will passivate: br.com.amadei.ejb._MyStatefulSessionBean_Serializable@15660e7
INFO: Will passivate: br.com.amadei.ejb._MyStatefulSessionBean_Serializable@1020406
INFO: Will passivate: br.com.amadei.ejb._MyStatefulSessionBean_Serializable@b3b029
This is printed by our callback method annotated with @PrePassivate and shows that our cache hint is working fine.
Now, we have to test activation, and this can be done invoking a business method (sayHello in our case) in a passivated instance of a stateful session bean.
The link in the page index.jsp calls another JSP page which has the logic necessary to activate the bean:
<a href="activate.jsp?id=<%=i%>">Click to Activate Bean <%=i%></a>
The activate.jsp source code contains the following:
<%
MyStatefulSessionBean bean =
(MyStatefulSessionBean)session.getAttribute(
request.getParameter("id"));
bean.sayHello();
%>
Activated: <%=bean%>
This code reclaims a bean from the HTTP session and invoke a business method on it. If we get one of the first ones of the list, it may have been passivated and it will be activated before we can use it. You will see the following message on the server output proving the bean was activated:
INFO: After activate: br.com.amadei.ejb._MyStatefulSessionBean_Serializable@1157f6e
So, in this post we created a way to prove how activation and passivation works for stateful session beans.