Srikanth Technologies

Accessing Stateful Session Bean From Web Tier

It is often required to access a stateful session bean from web tier. When using a stateful session bean from Servlet, one must NOT use dependency injection (DI).
Remember one servlet instance is used to handle all the requests of clients, whereas for stateful session bean we need to have a separate instance for each client.

So in order to access a stateful session bean from web tier (Servlets), we use HttpSession object to store a reference to EJB instance so that each client has a reference to a separate instance of EJB. We have to use JNDI, not DI.

I will show the steps and code required to create a stateful session bean and a servlet to access it.

Follow the steps below to create required project using NetBeans IDE 6.1.

  1. Create a new Enterprise project with GlassFish as the server. Select EJB and Web module in the project.
  2. Give name of the project as ent1. EJB module is called ent1-ejb, web module is called as ent1-war .
  3. Add a stateful session bean to EJB module with the name Books. Select Remote radio button and Stateful radio button. Enter package name as ent1 .
  4. NetBeans IDE creates BooksRemote.java and BooksBean.java and places them in ent1 package.
  5. Go to BooksBean.java and use right click -> EJB Methods -> Add Business Methods and add addBook () with a single String parameter, removeBook() with a single String parameter and returns true if books is successfully removed, getBooks() takes nothing but returns a Vector, and removeBooks() which takes nothing and returns void. The code for BooksRemote.java and BooksBean.java is given below.
// BooksRemote.java

package ent1;
import java.util.Vector;
import javax.ejb.Remote;
@Remote
public interface BooksRemote {
    void addBook(String title);
    Vector getBooks();
    boolean removeBook(String title);
    void removeBooks();
}
The following is the code for Bean class. It provides implementation for the methods in BooksRemote interface.
// BooksBean.java

package ent1;
import java.util.Vector;
import javax.annotation.PreDestroy;
import javax.ejb.Remove;
import javax.ejb.Stateful;
@Stateful
public class BooksBean implements BooksRemote {
    private Vector books = new Vector();
    public void addBook(String title) {
        books.add(title);
    }
    public Vector getBooks() {
        return books;
    }
    public boolean removeBook(String title) {
        if ( books.contains(title)) {
            books.remove(title);
            return true;
        }
        else
            return false;
    }
    // Remove method
    @Remove
    public void removeBooks() {
        System.out.println("About to destroy EJB instance ...");
    }
    
}

Code in Web Applications

Create an HTML page to take title from user. It contains two buttons – one to add book and one to display list of books.
<html>
  <body>
      <form action="books">
          Enter Book Title : <input type="Text" name="title" />
          <p/>
          <input type="submit" value="Add Book" name="op" />
          <input type="submit" value="List Books" name="op" />
          
      </form>
  
  </body>
</html>

The following is the servlet that is placed in ent1-war application to access EJB using JNDI and store reference to EJB in session object. We use <ejb-ref> element of web.xml to get access to EJB. So here is web.xml file that contains entries related to servlet and ejb reference.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <servlet>
        <servlet-name>BooksServlet</servlet-name>
        <servlet-class>BooksServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>BooksServlet</servlet-name>
        <url-pattern>/books</url-pattern>
    </servlet-mapping>
    <ejb-ref>
        <ejb-ref-name>ejb/books</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <home/>
        <remote>ent1.BooksRemote</remote>
    </ejb-ref>
</web-app>

Here is the code for servlet called BooksServlet with url pattern /books (as shown in web.xml).
import ent1.BooksRemote;
import java.io.*;
import javax.naming.InitialContext;
import javax.servlet.*;
import javax.servlet.http.*;
public class BooksServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            HttpSession s = request.getSession(true);
            BooksRemote books = (BooksRemote) s.getAttribute("booksbean");
            // if current session doesn't have an instance of EJB then get access to EJB and store reference to Session
            if (books == null) {
                InitialContext ctx = new InitialContext();
                books = (BooksRemote) ctx.lookup("java:comp/env/ejb/books");
                s.setAttribute("booksbean", books);
            }

            // findout the required operation - Add Book or List Books
            String op = request.getParameter("op");
            String title = request.getParameter("title");
            if (op.equals("Add Book")) {
                books.addBook(title);
            } else {
                for (String st : books.getBooks()) {
                    out.println(st +  "<br/>");
                }
            }
        } catch (Exception ex) {
            out.println(ex.getMessage());
        } finally {
            out.close();
        }
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
}
Deploy the entire enterprise application by right clicking on enterprise project and selecting option Undeploy and Deploy option from context (popup) menu. Start browser and enter the following URL to get access to HTML page that internally invokes servlet.
http://localhost:8080/ent1-war/books.html

Enter a title and click on Add Book button. Do it a few times to add a couple of books. Then click on List Books to get the list of books. Do it from different HTTP Sessions (enter URL from different browser instances) to see how different clients are associated with different EJB instances.