Java EE Stateful Session Bean (EJB) example (original) (raw)

In this article we are going to see how you can use Stateful Session Beans to keep track of state across a client Session in a simple Web Application.

1. Introduction

Stateful Session Beans usually hold information about a specific client’s session, and holds that information throughout the whole session (opposed to Stateless Session Beans). A Stateful EJB instance is coupled with only one client. One client can of course have many EJB instances is his session.

In this example we are going to create a simple Shopping Cart application. The session bean will hold a list of products. As the client adds more products to his cart, this list will grow accordingly. Finally the client will be able to checkout his order and the products on the aforementioned list will be persisted in a MySQL database.

To implement the above functionality, we are going to create an EAR Project and an EJB Project that will host our Session Bean and a Dynamic Web Application that will host a Servlet, testing the aforementioned behavior. We are going to use Eclipse Java EE IDE 4,3 Kepler and Glassfish 4.0 as our container. Additionally we are going to use standard JPA 2.o to persist our products in a MySQL 5.6.14 database running on localhost. Here is a guide on how to Integrate MySQL with Glassfish.

2. Create a new Enterprise Application Project

Create a new Enterprise Application Project named StatefulEJBEAR . In Eclipse IDE select File -> New -> Enterprise Application Project, fill in the form and click Finish:

new-ear-project

3. Create a new EJB Projet

Create a new EJB Project called StatefulSessionBeansEJB. We are going to create our session bean on this. Go to File -> New -> EJB Project and fill out the form. Be careful to select “Add EAR Project” and Select “StatefulEJBEAR” as EAR project name:

new-ejb-project

4. Create a Stateful Session Bean

Open StatefulSessionBeansEJB Project in the Project Explorer and in the folder ejbModule create a new source package named com.javacodegeeks.enterprise.ejb. In that package create a new Interface that will be a local view of the EJB:

Cart.java:

package com.javacodegeeks.enterprise.ejb;

import javax.ejb.Local;

import com.javacodegeeks.enterprise.product.Product;

@Local public interface Cart {

  void addProductToCart(Product product);

  void checkOut();

}

As you can see, we declare two methods, one to add a product to the cart and another to checkout the order.

And here is the Session Bean:

CartBean.java:

package com.javacodegeeks.enterprise.ejb;

import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct; import javax.ejb.Stateful; import javax.ejb.StatefulTimeout; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext;

import com.javacodegeeks.enterprise.product.Product;

@Stateful @StatefulTimeout(unit = TimeUnit.MINUTES, value = 20) public class CartBean implements Cart {

@PersistenceContext(unitName = "pu", type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

private List products;

@PostConstruct
private void initializeBean(){
   products = new ArrayList<>();
}

@Override
public void addProductToCart(Product product) {
     products.add(product);

}

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void checkOut() {
    for(Product product : products){
        entityManager.persist(product);
    }
    products.clear();

}

}

As you can see, our Session bean implements our Cart interface and simply holds a List of products (more on class Product later).

In the above code notice:

5. The Product Entity class

This is the object representing a simple product in our cart application. It consists of an id and a type. As we said, when the order is checked out we want the product on the cart to be persisted in a database. We used JPA 2.0 annotations to map Product class to a MySQL table. For this example, I’ve created a simple database named shop and table named product created with the script:

MySQL product table creation script:

CREATE TABLE product ( ID int(11) NOT NULL AUTO_INCREMENT, TYPE varchar(256) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (ID) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

So this is the table:

product-table

Let’s see the code of Product class:

Product.java:

package com.javacodegeeks.enterprise.product;

import java.io.Serializable;

import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table;

@Entity @Table(name = "PRODUCT", catalog = "shop") public class Product implements Serializable {

private static final long serialVersionUID = 1L;

@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "ID", nullable = false) private int id;

@Column(name = "TYPE", nullable = false) private String type;

public int getId() { return id; }

public String getType() { return type; }

public void setType(String description) { this.type = description; }

}

The above annotations are self explanatory. Very briefly, we use:

Finally, for the persistence to work we need to create a persistence.xml file inside ejbModule/META-INF folder. The file looks like this:

application.xml:

<persistence-unit name="pu" transaction-type="JTA">

    <jta-data-source>jdbc/MySQLDataSource</jta-data-source> 
    <class>com.javacodegeeks.enterprise.product.Product</class>
</persistence-unit>

Make sure you’ve integrated MySQL with Glassfish correctly using this quide. For more information on persistence.xml file you can see this Oracle guide.

So the final project structure of StatefulBeansEJB is :

ejb-project-structure

6. Create a new Dynamic Web Project

Go to File -> New -> Dynamic Web Project. Fill out the form and make sure you check “Add project to an EAR” and put StatefulEJBEAR as the “EAR project name”:

new-dynamic-web-project

After clicking “Finish”, go to the project Explorer and Right click on the Project StatefulSessionBeansTest and go to Properties-> Deployment Assembly -> Add -> Porject -> StatefulEJB :

deplyment-assembply

7. Create a new Servlet

Go to StatefulSessionBeansTest Web project and create a new Servlet named ShoppingCartServlet:

new-servlet

So this would be the final structure of the Web Project :

dynamic-web-project-structure

Here is the code of the Servlet:

ShoppingCartServlet.java:

package com.javacodegeeks.enterprise.servlet;

import java.io.IOException;

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 com.javacodegeeks.enterprise.ejb.Cart; import com.javacodegeeks.enterprise.product.Product;

@WebServlet("/ShoppingCartServlet") public class ShoppingCartServlet extends HttpServlet {

private static final long serialVersionUID = 1L;
private static final String CART_SESSION_KEY = "shoppingCart";

public ShoppingCartServlet() {
    super();

}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    System.out.println("Hello from servlet");

    Cart cartBean = (Cart) request.getSession().getAttribute(CART_SESSION_KEY);

     if(cartBean == null){
          // EJB is not yet in the HTTP session
          // This means that the client just sent his first request
          // We obtain a CartBean instance and add it to the session object.
          try {
            InitialContext ic = new InitialContext();
            cartBean = (Cart) 
             ic.lookup("java:global/StatefulEJBEAR/StatefulSessionBeansEJB/CartBean!"
             		+ "com.javacodegeeks.enterprise.ejb.Cart");

            request.getSession().setAttribute(CART_SESSION_KEY, cartBean);

            System.out.println("shoppingCart created");

          } catch (NamingException e) {
            throw new ServletException(e);
          }
     }

     String productName = request.getParameter("product");
     if(productName != null && productName.length() > 0){

          Product product = new Product();
          product.setType(productName);
          cartBean.addProductToCart(product);

          System.out.println("product "+productName+" added");
     }

     String checkout = request.getParameter("checkout");
     if(checkout != null && checkout.equalsIgnoreCase("yes")){
          // Request instructs to complete the purchase
          cartBean.checkOut();
          System.out.println("Shopping cart checked out ");
     }

}

}

In the above Serlvet, when the user sents a GET request for the fist time, a new CartBean instance will be obtained from the container and added to the session. Then the product query parameter is parsed, and if it’s not null a new Product with type productName, and will e added to the list of products in the session bean.

Then the checkout query parameter is parsed and if it’s evaluated to 'yes' the products in the session bean will be persisted.

Tip: If you are having trouble figuring out the Portable JNDI names for EJB PassivationObject look at the logs or output of Glassfish when deploying the project and you will find a line like this : 2013-12-13T18:22:28.598+0200|INFO: EJB5181:Portable JNDI names for EJB PassivationObject: (java:global/StatefulBeans/StatefulEJB/PassivationObject, java:global/StatefulBeans/StatefulEJB/PassivationObject!com.javacodegeeks.enterprise.ejb.Passivation)

8. Test

Now we are simply going to deploy the Dynamic Web Application to Glassfish, and add some products on the cart. Then we will request to checkout the order.

Let’s say we want to add some products, we can issue the following requests :

http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?product=ram http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?product=mouse http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?product=ssd

While posting these requests this is the output from the console:

2014-01-07T22:02:07.622+0200|INFO: Hello from servlet
2014-01-07T22:02:07.684+0200|INFO: shoppingCart created
2014-01-07T22:02:07.687+0200|INFO: product ram added
2014-01-07T22:02:12.236+0200|INFO: Hello from servlet
2014-01-07T22:02:12.237+0200|INFO: product mouse added
2014-01-07T22:02:24.851+0200|INFO: Hello from servlet
2014-01-07T22:02:24.851+0200|INFO: product ssd added

Now to checkout the order you can issue:

http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?checkout=yes

This is the output from the console:

2014-01-07T22:19:46.444+0200|INFO: Hello from servlet
2014-01-07T22:19:46.537+0200|INFO: Shopping cart checked out

Here you can see the products on the database :

mysql-terminal

Dowload Eclipse Project

This was an example on Java EE Stateful Session Bean (EJB). Here are the Eclipse Projects of this example : StatefulEJBS.zip

Photo of Nikos Maravitsas

Nikos has graduated from the Department of Informatics and Telecommunications of The National and Kapodistrian University of Athens.