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]


 

No comments: