Showing posts with label EJB. Show all posts
Showing posts with label EJB. Show all posts

Wednesday, July 04, 2012

Stateful Session Bean using EJB 3.0

The Data Transfer (Domain) object 
package com.test.snippets.enterprise;

import java.io.Serializable;
import java.util.Date;

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

@Entity
public class Employee implements Serializable {
    
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String name;
    private String surname;
    private String title;
    private Double salary;
    private Date created;
    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    public String getSurname() {
        return surname;
    }
    public void setSurname(String surname) {
        this.surname = surname;
    }
    
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    
    public Double getSalary() {
        return salary;
    }
    public void setSalary(Double salary) {
        this.salary = salary;
    }
    public Date getCreated() {
        return created;
    }
    public void setCreated(Date created) {
        this.created = created;
    }
    
    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", surname=" + surname
                + ", title=" + title + ", salary="+salary+ ", created=" + created+"]";
    }

} 
The EJB implementation class 
 
package com.test.snippets.enterprise;

import java.util.Collection;
import java.util.Date;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.ejb.PrePassivate;
import javax.ejb.PostActivate;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;

@Stateful
public class EmployeeService implements EmployeeServiceLocal, EmployeeServiceRemote {

    /*
     * With a Stateful Session Bean a Persistent Context of EXTENDED Type can be used.
     * Usually, an EntityManager lives and dies within a JTA transaction. Once the 
     * transaction is finished, all persistent objects are detached from the EntityManager 
     * and are no longer managed. Any local caching the EntityManager instance had done is lost. 
     * In addition you can define long-living EntityManagers that live beyond the scope of a JTA 
     * transaction. This is called an Extended Persistence Context. When you specify that an 
     * injected EntityManager is an extended persistence context, all object instances remain 
     * managed. Extended persistence contexts can only be used within Stateful session beans.
     */
    @PersistenceContext(unitName = "TutorialPU", type = PersistenceContextType.EXTENDED)
    EntityManager entityManager;

    public EmployeeService() {
    }

    public Employee createEmployee(String name, String surname, String title, double salary) {
        Employee employee = new Employee();
        employee.setName(name);
        employee.setSurname(surname);
        employee.setTitle(title);
        employee.setSalary(salary);
        employee.setCreated(new Date());

        entityManager.persist(employee);

        return employee;
    }

    public void removeEmployee(long id) {
        Employee employee = findEmployee(id);
        if (employee != null) {
            entityManager.remove(employee);
        }
    }

    public Employee promoteEmployee(long id, String newTitle, double newSalary) {
        Employee employee = entityManager.find(Employee.class, id);
        if (employee != null) {
            employee.setTitle(newTitle);
            employee.setSalary(newSalary);
        }
        return employee;
    }

    public Employee findEmployee(long id) {
        return entityManager.find(Employee.class, id);
    }

    public Collection<Employee> findAllEmployees() {
        Query query = entityManager.createQuery("SELECT e FROM Employee e");
        return (Collection<Employee>) query.getResultList();
    }
    
    // Lifecycle operations
    
    @PostConstruct
    public void PostConstruct() {
      System.out.println("PostConstruct");
    }
    
    @PostActivate
    public void PostActivate() {
      System.out.println("PostActivate");
    }
    
    @PrePassivate
    public void PrePassivate() {
      System.out.println("PrePassivate");
    }
    
    @PreDestroy
    public void shutdown() {
      System.out.println("PreDestroy");
    }
    
    @Remove
    public void remove() {
      System.out.println("Remove");
    }

} 
The EJB local interface (suitable for in VM communication) 
package com.test.snippets.enterprise;

import java.util.Collection;

import javax.ejb.Local;

@Local
public interface EmployeeServiceLocal {

    public Employee createEmployee(String name, String surname, String title, double salary);
    public void removeEmployee(long id);
    public Employee promoteEmployee(long id, String newTitle, double newSalary);
    public Employee findEmployee(long id);
    public Collection<Employee> findAllEmployees();
    
} 
The EJB remote interface (suitable for intra VM communication) 
package com.test.snippets.enterprise;

import java.util.Collection;

import javax.ejb.Remote;

@Remote
public interface EmployeeServiceRemote {
    
    public Employee createEmployee(String name, String surname, String title, double salary);
    public void removeEmployee(long id);
    public Employee promoteEmployee(long id, String newTitle, double newSalary);
    public Employee findEmployee(long id);
    public Collection<Employee> findAllEmployees();
    
} 
The persistence.xml file driving the JPA framework 
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
  <persistence-unit name="TutorialPU" >
        <jta-data-source>java:/DefaultDS</jta-data-source>
        <properties>
         <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
        </properties>
<!--
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
      <property name="hibernate.connection.username" value="sa"/>
      <property name="hibernate.connection.password" value=""/>
      <property name="hibernate.connection.url" value="jdbc:hsqldb:data/tutorial"/>
    </properties>
-->    
  </persistence-unit>
</persistence> 
 
The application.xml file describing the modules in the .ear archive
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/j2ee" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"
             version="1.4">
  <display-name>ExampleEJB3</display-name>

  <module>
     <java>exampleEJB3-persistence.jar</java>
  </module>

  <module>
     <ejb>exampleEJB3.jar</ejb>
  </module>

</application> 
 
The structure of the .ear archive 
exampleEJB3.ear
 |
 |_exampleEJB3-persistence.jar 
 |  |_com
 |  |  |_test
 |  |     |_snippets
 |  |        |_enterprise
 |  |           |_Employee.class
 |  |_META-INF
 |     |_persistence.xml
 |
 |_exampleEJB3.jar
 |   |_com
 |   |  |_test
 |   |     |_snippets
 |   |        |_enterprise
 |   |           |_EmployeeService.class
 |   |           |_EmployeeServiceLocal.class
 |   |           |_EmployeeServiceRemote.class
 |   |_META-INF
 |
 |_META-INF
    |_application.xml 
 
An example client 
package com.javacodegeeks.snippets.enterprise;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InitialContext;


public class EmployeeServiceClient {

    public static void main(String[] a) throws Exception {

        /*
         * Connecting to JBoss naming service running on local host and on
         * default port 1099 the environment that should be created is like the
         * one shown below :
         */
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
        env.put(Context.PROVIDER_URL, "jnp://localhost:1099");
        env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
        
        Context ctx = new InitialContext(env);
        
        // We get a reference of the remote EJB interface to invoke its business methods
        EmployeeServiceRemote employeeService = (EmployeeServiceRemote) ctx.lookup("exampleEJB3/EmployeeService/remote");
        
        Employee employee = employeeService.createEmployee("Byron", "Kiourtzoglou", "Master Software Engineer", 2000d);
        
        long employeeId = employee.getId();
        
        System.out.println(employeeService.findEmployee(employeeId));
        
        employeeService.promoteEmployee(employeeId, "Principal Software Engineer", 3000d);
        
        System.out.println(employeeService.findEmployee(employeeId));

    }

} 
Output:

Employee [id=1, name=Byron, surname=Kiourtzoglou, title=Master Software Engineer, salary=2000.0, created=2011-12-03 17:31:30.203]
Employee [id=1, name=Byron, surname=Kiourtzoglou, title=Principal Software Engineer, salary=3000.0, created=2011-12-03 17:31:30.203]


 

Statefull Session Bean using EJB2.0

EJB Hello World Project Structure

EJBHome and EJBObject in EJB

Client can not directly create object of session, entity or message driven beans. Ok
let’s try to get in to depth of how session and entity beans can be accessed by end clients.
There are two important interfaces which needs to be used in order that we can create
and use session, entity and message driven bean objects:-

Bean Interface
Client uses the Bean interface to communicate with the session bean which resides on the
EJB application server. The Bean interface extends the EJBObject interface of the
javax.ejb package. This interface has all the methods, functions which the final session
bean has.

Home Interface
In order the client gets a reference to the Bean interface it must call the Beans home
interface. The Home interface extends EJBHome interface of the javax.ejb package.
Home Interface of a bean is responsible for creating the object and giving the reference
of the Bean interface.


Above figure depicts the complete flow of how the Java application or the Java client
gets a reference of the customer bean interface. 
Step1 Java application calls the home interface to get a reference of customer session object. 
Step2 Home interface then creates an object of customer session bean which can be referenced by using customer bean interface.
Step3 java clients gets reference of the customer session bean object through
customer bean interface.

Local interfaces :
On of the biggest issues of creating objects using home interface is performance. Below
are the steps which follow when you call the EJB object:-
  • JAVA client calls the local stub.
  • Stub marshal the values in to some other form which the network understands and sends it to the skeleton.
  • Skeleton then de-marshals it back to a form which is suitable for JAVA.Skeleton then calls the EJB object and methods.
  • EJB object then does object creation, connection pooling, transaction etc.
  • Once EJB object calls the bean and the bean completes its functionalities. All the above steps must again be repeated to reach back to the JAVA client.

So you can easily guess from the above step that its lot of work. But this has been improved in EJB 2.0 using Local objects. Local objects implement local interface rather than using
remote interface. Just to have a comparison below are the steps how the local object
works.
  • JAVA client calls the local object.
  • Local object does connection pooling, transactions and security.
  • It then passes calls the bean and when bean completes its work it returns the data to the Local object who then passes the same to the end client.
You can understand from the above steps we have by passed completely marshalling and
de-marshalling.
Limitations of using Local object?
Local object only work if you are calling beans in the same process. Second they marshal
data by ref rather than by Val. This may speed up your performance but you need to
change semantics for the same. So finally it’s a design and the requirement decision. If
you are expecting to call beans remotely then using local object will not work.

Passivation and Activation in EJB

When we are dealing with stateful session beans we need to store the client conversation
of the bean so that it can be available in client’s next request. But when we talk about
server it has limited resources. If the conversation of the bean is large then the server can
run out of resource. So in order to preserve resources EJB server swaps this conversational
data in memory to hard disk thus allowing memory to be reclaimed. This process of
saving the memory data to hard disk is called as “Passivation”. Now when the client
comes back the conversational data is again swapped from the hard disk to the bean. This
process is called as “Activation”. The container informs the bean that its about to passivate or activate using the "ejbPassivate()" and "ejbActivate()" methods.

Can beans who are involved in transaction have “Passivation” process?
No.
How does the server decide which beans to passivate and activate? 
Most servers use the (LRU) Last Recently Used time as a strategy. Which mean passivate
the beans which have been called recently.
In what format is the conversational data written to the disk?
Bean conversational data is saved in the disk as serialized object. This is possible because
“javax.ejb.EnterpriseBean” implements “java.io.Serializable” interface. So during
passivation time it converts the bean conversational data to a bit-blob and during activationit just reverses the process.

Life cycle for Stateless and Stateful beans

Life cycle for stateless session beans

  • When the application server is not started or just starting there are no instances of beans.
  • EJB Container looks in to the pooling policy and instantiates new beans accordingly. For instance if the pooling policy says to create a pool of 10 object it will createaccordingly.
  • Container instantiates the bean using “Class.newInstance(“MyBean.class”).
  • After the object is created EJB container calls the “setSessionContext()” to set the context object so that bean can make a call back to the container if it ever needs to.
  • Container then calls “ejbCreate()” method and this initializes you bean. Just a note to make when a client makes a new object or destroys an EJB object. It’s not necessary that EJB container will do it instantly. It will decide that whether it should really destroy this object or move it pool or should not create an object and take one from the pool.
  • Finally container makes calls to the business methods of the bean. All the business methods are called depending on the client makes calls. All the method calls are treated in the same way as session beans are in the same state after the method call. When a request comes in from client1 the container can take bean1 from the pool process the request and bring bean1 to a previous state. Later when again client1 calls container can take bean2 process the request and bring bean2 to the previous state. So the object treats every request as a new request and does not care to save the previous data of the request.
  • Finally when the container is about the remove the object it calls the “ejbRemove()” of the bean.

Life cycle of stateful session beans 
Life cycle of the stateful session beans is same as stateless only leaving the below points:-
  • First as its stateful there is no pool of objects.
  • Second with every client call there are “ejbPassivate” and “ejbActivate” methods to save and retain the conversational state.

Enterprise Java Beans (EJB)

EJB is a standard for building server side components in JAVA. It specifies an agreement
between components and application servers that enables any component to run in any
application server. EJB components are deployable and can be imported in to an application server which hosts these components. EJB are not intended for client side they are server side components. They are specially meant for complex server side operations like executing complex algorithms or high volume business transactions.

There are three kinds of EJB’s:-
Session beans
Session beans are construct in EJB. They represent business logic of an application. They
represent a group of logical related functionality. For instance you can have a customer
session bean which can have functionality like customer interest calculation, customer
reporting, customer tax calculation etc. But as these functionalities logically belong to
customer they will be included in the customer session bean. In short session bean has
business logic.

There are two types of session beans:-
Stateless: - they do not maintain state across method calls. So every time client makes a
call it’s like a new object from scratch.
Stateful:— These beans can hold client state across method invocations. This is possible
with the use of instance variables declared in the class definition. Every time the client
calls it they can get there previous states.
Stateless session bean provide greater scalability as EJB container does not have to
maintain state across method invocations. Storing state for EJB container is huge activity.
Entity beans
Entity bean represent persistent data in an EJB application. They provide object-oriented
abstraction to a relational database. When Session bean needs to access data it called the
entity beans. Entity beans do read, write, update and delete from tables. For instance you
have a customer table then you will have customer entity bean which maps to the table
and can do the CRUD (Create, Read, Update and Delete) operation to the customer
table. From architecture angle you can think entity bean as the data access layer of a
system.

Message-driven beans
There are situations in project where you would like to communicate asynchronously
with some other systems. This is achieved by using message-driven beans. For instance
when user places order you would like to submit it asynchronously to the order system
and then move ahead with some other work. You would then later comeback after sometime
to see if the order is completely or the order system will notify you about the completion
of the order.