Lecture #7: Introduction to EJB-Session Beans

CPAN423 Enterprise Java Programming

Lecture #7: Introduction to EJB-Session Beans

Enterprise Java Beans is one of the Java-based distributed component technologies for building business logic in enterprise solutions. EJB applications run in a multithreaded environment where the EJB component(s) implements the business logic. EJB components execute within an EJB container, which is managed by an application server. EJB applications can be distributed across many tiers, but the 3 tiers architecture is most widely used. The 3 tiers architecture consists of the layers: presentation, business logic, and database.

In the client tier the application client container runs and manages the client application. In the middle tier the web container manage JSP and servlets and the EJB container manages the execution and life cycle of all the EJB on the server. The web and EJB containers provide all the required system level services such as transaction management, state management, security, database pooling, performance and concurrency. Since the client in the presentation tier focuses on implementing the presentation logic and use EJB for business methods, it is called thin client.

The following diagram shows the architecture of 3 tiers enterprise Java beans application:

There are three types of EJB: Session, Entity, and Message Driven. This lecture focuses on Session beans. Entity and Message Driven are covered in the next lectures

An instance of a session beans handles business logic methods for one or more clients. Session beans are not persistent, which means that session EJB do not store their data into a database. If the Server crashes, all session EJB instance are lost including their data. However. Session beans may maintain status during an interactive session with the client.

There are two types of session beans:

·  Stateful: An instance of stateful session beans stores data for a particular client and maintain state during the client calls to methods of this bean. The EJB container creates new stateful session bean instance for each client. The stateful session bean has three states: Do not exist, Ready and Passive. The stateful session bean transition to Ready state after the container creates an instance of this bean. The container does that by calling the methods Class.newInstance, setSessionContext and ejbCreate in sequence. This bean transit to Do not exist state when the client terminates the session. The container does that by calling ejbRemove method. The container also transitions the stateful session bean to a passive state to free some memory resources by moving the bean from the memory to the secondary storage by calling ejbPassivate method. If a client calls a method of a passive stateful session bean, the container transition the bean to Ready state by calling ejbActivate method.

·  Stateless: An instance of a stateless session bean does not store data that are specific to a particular client. The EJB container creates a pool of instances from the same stateless session bean. Any available instance can be assigned for a client request. The EJB container makes this instance available after the client finishes calling the bean’s methods. The stateless session bean has two states: Do not exist, and Ready. The stateless session transition to Ready state after the container creates an instance of this bean. The container does that by calling the methods Class.newInstance, setSessionContext and ejbCreate in sequence. This bean transition to Do not exist state when there is no more requests for its instance. The container does that by calling ejbRemove method. Stateless session exhibit high performance and is scalable for large number of clients.

The client of a session bean invokes business methods of the bean through a bean interface. Two types of interfaces are possible with session bean (also with an entity bean):

·  Home and Remote Interfaces: Enables clients to access a bean remotely. The remote interface defines the business methods of the bean. The Home interface defines the life cycle methods of the bean. Remote client can be JSP, servlet, J2EE application client , or another EJB.

·  Local Home and Local Interfaces: Enables clients to access a bean locally. The Local interface defines the business methods of the bean. The Local Home interface defines the life cycle methods of the bean. Local client can be JSP, servlet, another EJB, but not a J2EE application client.

The EJB implementation class provides implementation for the bean’s business and life cycle methods. The EJB container provides an environment for running EJB and manages the life cycle of the EJB. The EJB container is included within an application server that provides system level services.

To perform a certain business transaction, business methods must be called in a specific sequence. The transaction is committed if all the required steps are executed properly and rolled back if any step is not executed properly. The boundary of the transaction (start and end) is called transaction demarcation. J2EE supports two methods for managing transactions: programmatic (bean-managed transaction demarcation ) and declarative (container-managed transaction demarcation). The EJB developer can either write the code to managed transaction demarcation manually, or use declarative in the EJB deployment descriptor to specify the method(s) that requires container-managed transaction and their attributes. Session beans support the two methods of transaction management. The textbook provides some transaction management examples with session beans on pages 879-890.

Examples:

Ex1: Stateless Session Bean example with a servlet as a client:

This example creates a remote stateless session beans that checks a user login and will e used by a servlet.. First we will write a remote interface called PersonalInterface that has the following content:

package Login;

import java.rmi.*;

import javax.ejb.*;

public interface PersonalInterface extends EJBObject

{

boolean check(String name, String pass) throws RemoteException;

}

Then we will write a Home interface called PersonalInterafaceHome that has the following content:

package Login;

import java.rmi.*;

import javax.ejb.*;

public interface PersonalInterfaceHome extends EJBHome

{

public PersonalInterface create() throws RemoteException, CreateException;

}

Then we will provide a class called PersonalInterfaceBean that provide implementation for the method check of the remote interface PersonalInterface. This method will loop through two arrays of names and passwords to validate the user login. The user login(name/password) should be passed as parameters to check method. If a matching is found then check will return true, otherwise it will return false. PersonalInterfacBean.java should have the following content:

package Login;

import java.rmi.*;

import javax.ejb.*;

public class PersonalInterfaceBean implements SessionBean

{

/*

define two arrays for users’ names and passwords

*/

private String [] userName={"a","b","c"};

private String [] userPassword={"1","2","3"};

public void ejbCreate() { }

public void setSessionContext(

SessionContext ctx) { }

public void ejbRemove() { }

public void ejbActivate() { }

public void ejbPassivate() { }

public boolean check(String name, String pass)

{

boolean found=false;

for (int i=0;i<userName.length;i++)

if (userName[i].equals(name) & userPassword[i].equals(pass))

found=true;

return found;

}

}

The following is a Servlet called LoginServlet that obtain a remote reference to the PersonalInterface object, and call check method to validate the user login.

import java.io.*;

import javax.ejb.*;

import javax.naming.*;

import javax.servlet.*;

import javax.rmi.PortableRemoteObject;

import javax.servlet.http.*;

import Login.*;

public class LoginServlet extends HttpServlet {

/**

* The servlet stores the home interface after the initial lookup.

* Since the home interface never changes, caching the lookup will save

* some performance.

*/

private PersonalInterfaceHome piHome=null;

/**

* The init method looks up the HelloHome interface using JNDI and

* stores it in a servlet variable.

*/

public void init() throws ServletException

{

try {

/*

* Look up the remote EJB context using JNDI.

* The context contains the remote EJB beans.

*/

Context ctx = new InitialContext();

piHome = (PersonalInterfaceHome) ctx.lookup("java:comp/env/ejb/login");

}

catch (NamingException e)

{

throw new ServletException(e);

}

}

public void doPost (HttpServletRequest req, HttpServletResponse res)

throws ServletException, IOException

{

res.setContentType("text/html");

PrintWriter out = res.getWriter();

String uName=req.getParameter("userName");

String uPassword=req.getParameter("userPassword");

try

{

PersonalInterface pi= piHome.create();

if (pi.check(uName,uPassword))

{

out.println("Login correct");

}

else

{

out.println("Login inccorrect <a href='http://localhost:8080/SessionEJB/loginEJB.html'> try again </a>");

}

}

catch(Exception e)

{

out.print( e.toString());

}

}

}

And here is an HTML file called loginEJB.html that will be used to invoke the LoginServlet:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<title>Login Example</title>

</head>

<body>

<form method="post" action="http://localhost:8080/SessionEJB/login"

Enter User Name: <input type="text" name="userName" size="20" /<br>

Enter User password: <input type="password" name="userPassword" size="10" /<br>

<input type="submit" value="Login">

</form>

</html>

EJB applications are deployed under webapps folder of Resin web server. We will deploy our EJB under a folder called SessionEJB. The following steps illustrate the required steps:

·  Create a folder called SessionEJB under webapps folder.

Any HTML or JSP file should be stored in SessionEJB folder.

·  Under SessionEJB folder create a folder called WEB-INF. WEB-INF contain the web application deployment descriptor files: web.xml and one EJB descriptor file for each beans deployed under SessionEJB folder.

o  Under WEB-INF create the following folders:

§  classes: contains the servlet classes, the EJB classes and any other supporting classes. We will package our EJB classes into a folder called Login.

§  lib: Contain any JAR file used in the web application. JARs can contain EJB, servlets and other supporting classes.

The resulting structure should look as follow:

webapps

SessionEJB

WEB-INF

classes

Login

lib

The files PersonalInterface.java, PersonalInterfaceHome.java and PersonalInterfaceBean.java should be stored under Login folder. LoginServlet.java should be stored under classes folder. loginUser.html should be stored under SessionEJB folder.

Following is an EJB descriptor file called login.ejb that should be stored under WEB-INF folder:

<?xml version="1.0"?>

<ejb-jar xmlns="http://caucho.com/ns/resin">

<enterprise-beans>

<session>

<!--

- The ejb-name is used for the JNDI lookup to find the home interface

-->

<ejb-name>login</ejb-name>

<!--

- home defines the bean's remote home interface.

-->

<home>Login.PersonalInterfaceHome</home>

<!--

- remote defines the bean's remote interface.

-->

<remote>Login.PersonalInterface</remote>

<!--

- stateless session beans are like servlets without HttpSession.

-->

<!--

- ejb-class defines the bean's implementation class.

-->

<ejb-class>Login.PersonalInterfaceBean</ejb-class>

<session-type>Stateless</session-type>

<!--

- The container handle the transactions.

-->

<transaction-type>Bean</transaction-type>

</session>

</enterprise-beans>

</ejb-jar>

Following is the web application deployment descriptor for this application (web.xml) that should be stored under WEB-INF folder:

<web-app xmlns="http://caucho.com/ns/resin">

<!-- EJB Server configuration -->

<ejb-server config-directory="WEB-INF"/>

<servlet servlet-name='hessian' servlet-class='com.caucho.hessian.EJBServlet'/>

<servlet-mapping url-pattern='/hessian/*' servlet-name='hessian'/>

<servlet servlet-name='count' servlet-class='CountServlet'/>

<servlet-mapping url-pattern='/count' servlet-name='count'/>

<!-- Configuration for the client.

-

- Normally, this would not be in the same web.xml as the server

- because the client and the server would be separate. For the

- purposes of this tutorial, both the client and the server are in the

- same web-app

-->

<!-- a alternative client servlet that uses JNDI -->

<servlet servlet-name='login' servlet-class='LoginServlet'/>

<servlet-mapping url-pattern='/login/*' servlet-name='login'/>

<jndi-link jndi-name='java:comp/env/ejb'

factory='com.caucho.hessian.HessianContextFactory'>

<init-param java.naming.provider.url='${app.url}/hessian'/>

</jndi-link>

</web-app>

The login form in this example can be invoked by typing the following in the browser URL: http://localhost:8080/SessionEJB/loginEJB.html

Ex2: EJB stateless session bean example with JSP as a client

In this example we will build a JSP called login.jsp that will use the stateless session bean defined in Ex1. The procedure for compiling and running the remote session bean is the same as in Ex1. The JSP page should be saved under SessionEJB folder.

<%@ page import="Login.*, javax.ejb.*, javax.naming.*,javax.rmi.PortableRemoteObject" %>

<%!

public PersonalInterfaceHome piHome;

// Get the home stub once and save it in home

public void jspInit()

{

super.jspInit();

try {

Context ctx = new InitialContext();

piHome = (PersonalInterfaceHome) ctx.lookup("java:comp/env/ejb/login");

} catch (NamingException e)

{

e.printStackTrace();

}

}

%>

<%

try

{

PersonalInterface pi= piHome.create();

String uName=request.getParameter("userName");

String uPassword=request.getParameter("userPassword");

if (pi.check(uName,uPassword))

{

out.println("Login correct");

}

else

{

out.println("Login inccorrect <a href='http://localhost:8080/SessionEJB/loginEJBJSP.html'> try again </a>");

}

}

catch(Exception e)

{

out.print( e.toString());

}

%>

Below is an HTML form called loginEJBJSP.html that will invoke login.jsp:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<title>Login Example</title>

</head>

<body>

<form method="post" action="http://localhost:8080/SessionEJB/login.jsp">

Enter User Name: <input type="text" name="userName" size="20" /<br>

Enter User password: <input type="password" name="userPassword" size="10" /<br>

<input type="submit" value="Login">

</form>

</html>

Both login.jsp and loginEJBJSP.html should be store under SessionEJB folder.

loginEJBJSP.html can be invoked by typing the following in the browser URL: http://localhost:8080/SessionEJB/loginEJBJSP.html

Ex3: EJB stateful session bean example with JSP as a client

This example creates a remote stateful session beans that counts the number of hits and will e used by a JSP. First we will write a remote interface called CountInterface that has the following content:

package counter;

import java.rmi.*;

import javax.ejb.*;

public interface CountInterface extends EJBObject {

int returnCount() throws RemoteException;

}

Then we will write a Home interface called CountInterafaceHome that has the following content:

package counter;

import java.rmi.*;

import javax.ejb.*;

public interface CountInterfaceHome extends EJBHome {

public CountInterface create() throws RemoteException, CreateException;

}

Then we will provide a class called CountInterfaceBean that provide implementation for the method returnCount of the remote interface CountInterface. This method will increment the count variable each time it will be called. count is called state variable.

package counter;

import java.rmi.*;

import javax.ejb.*;

public class CountInterfaceBean implements SessionBean

{

private int count;

public void ejbCreate() { }

public void setSessionContext(

SessionContext ctx) { }

public void ejbRemove() { }

public void ejbActivate() { }

public void ejbPassivate() { }

public int returnCount()

{

return count++;

}

}

Below is a JSP file called count.jsp that will use this stateful session bean.

<%@ page import="counter.*, javax.ejb.*, javax.naming.*,javax.rmi.PortableRemoteObject" %>

<%!

private CountInterfaceHome cntHome;

// Get the home stub once and save it in home