EJB 3.0 outside the Container
!Overview
One of the most important features added to the EJB 3.0 specification is the ability to use the persistence API outside the container. This means that Java 5.0 standard edition will benefit from all the persistence features available in the enterprise edition. In this article we will try to implement the example that comes with the specification and run it on a Java 5.0 platform.
!The Example
The proposed final draft of the EJB 3.0 Java Persistence API specification lists a good example showing some of the important and commonly used features of the specification. Because this is a proposed draft version of the API specification, some minor changes to the listed code will be needed. The following class diagram shows the example classes and their relationships:\\
|>

Now let's give this example a try.
!Preparing the environment
To implement this example, we will use the Hibernate implementation of JSR-220. Our implementation will use the following versions:\\
- Hibernate 3.1.2\\
- Hibernate Annotations 3.1 Beta 8\\
- Hibernate EntityManager 3.1 Beta 6\\
We need to add the following files to our class path:\\
- hibernate.properties: Add your connection properties here\\
- log4j.properties: Log4J configuration\\
This may sound familiar if you hibernated before. A new XML descriptor is required by the specification which makes your code portable across different implementations of the API. This file must be named persistence.xml and should go under META-INF directory of your class path. The contents of the file for our example are listed below:
{{{
org.hibernate.ejb.HibernatePersistence
}}}
If you are using a database engine other than Oracle, you should change the properties here and in the hibernate.properties file as required. We don't need any hibernate mapping descriptors in our example.\\
!Creating the Entities
As previously said, you will need to do some modifications to the example that comes with the specification; a modified version is [attached|http://www.egjug.org/files/ejb-3.0-sample-src.zip] with this article. Here is a sample of the Employee Entity class:
{{{
package org.egjug.tips.ejb.domain;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
import static javax.persistence.GenerationType.*;
import static javax.persistence.CascadeType.*;
@Entity
@Table(name = "EMPL")
@SecondaryTable(name = "EMP_SALARY",
pkJoinColumns =
@PrimaryKeyJoinColumn(name = "EMP_ID",
referencedColumnName = "ID"))
public class Employee implements Serializable{
private int id;
private int version;
private String name;
private Address address;
private Collection phoneNumbers;
private Collection
projects;
private Long salary;
private EmploymentPeriod period;
@Id
@GeneratedValue(strategy = SEQUENCE)
public Integer getId(){
return id;
}
protected void setId(Integer id){
this.id = id;
}
@Version
@Column(name = "EMP_VERSION", nullable = false)
public int getVersion(){
return version;
}
protected void setVersion(int version){
this.version = version;
}
@Column(name = "EMP_NAME", length = 80)
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
@ManyToOne(cascade = PERSIST, optional = false)
@JoinColumn(name = "ADDR_ID",
referencedColumnName = "ID", nullable = false)
public Address getAddress(){
return address;
}
public void setAddress(Address address){
this.address = address;
}
@OneToMany(targetEntity = PhoneNumber.class,
cascade = ALL, mappedBy = "employee")
public Collection getPhoneNumbers(){
return phoneNumbers;
}
public void setPhoneNumbers(Collection phoneNumbers){
this.phoneNumbers = phoneNumbers;
}
@ManyToMany(cascade = PERSIST)
@JoinTable(
name = "EMP_PROJ",
joinColumns = @JoinColumn(
name = "EMP_ID", referencedColumnName = "ID"),
inverseJoinColumns = @JoinColumn(
name = "PROJ_ID", referencedColumnName = "ID"))
public Collection getProjects(){
return projects;
}
public void setProjects(Collection projects){
this.projects = projects;
}
@Column(name = "EMP_SAL", table = "EMP_SALARY")
public Long getSalary(){
return salary;
}
public void setSalary(Long salary){
this.salary = salary;
}
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "startDate",
column = @Column(name = "EMP_START")),
@AttributeOverride(name = "endDate",
column = @Column(name = "EMP_END"))
})
public EmploymentPeriod getEmploymentPeriod(){
return period;
}
public void setEmploymentPeriod(EmploymentPeriod period){
this.period = period;
}
}
}}}
!Sample Usage
The following is a sample usage of our entity beans; notice that the code is not referencing any Hibernate specific class:
{{{
package org.egjug.tips.ejb;
import org.egjug.tips.ejb.domain.*;
import javax.persistence.*;
import java.util.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;
public class Controller{
private EntityManager em;
public Controller(){
Map properties = new HashMap();
EntityManagerFactory emf = Persistence.createEntityManagerFactory("em", properties);
em = emf.createEntityManager();
}
public void close(){
em.close();
}
public static Address createAddress(String city, String street){
Address address = new Address();
address.setCity(city);
address.setStreet(street);
return address;
}
public static Date toDate(String sdate){
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
Date date;
try{
date = sdf.parse(sdate);
}
catch(ParseException e){
date = new Date();
}
return date;
}
public static EmploymentPeriod createEmploymentPeriod(String from, String to){
EmploymentPeriod ep = new EmploymentPeriod();
ep.setStartDate(toDate(from));
ep.setEndDate(toDate(to));
return ep;
}
public static List createProjects(){
List projects = new ArrayList();
Project p1 = new Project();
p1.setName("Project-X");
GovernmentProject p2 = new GovernmentProject();
p2.setName("G-Project-Y");
p2.setFileInfo("FileInfo");
CovertProject p3 = new CovertProject("Yes");
p3.setName("C-Project-Z");
projects.add(p1);
projects.add(p2);
projects.add(p3);
return projects;
}
public static Employee createEmployee(String name,
Address address,
EmploymentPeriod ep,
Long salary,
Collection projects){
Employee employee = new Employee();
employee.setName(name);
employee.setAddress(address);
employee.setEmploymentPeriod(ep);
employee.setSalary(salary);
employee.setProjects(projects);
return employee;
}
public void doTransaction(){
EntityTransaction tx = em.getTransaction();
List projects = createProjects();
Employee tamer =
createEmployee("Tamer Al-Tammoor",
createAddress("Cairo", "Abbas Al-Akkad"),
createEmploymentPeriod("01-01-2005", "11-10-2010"),
1500L,
projects);
Employee nader =
createEmployee("Nader Al-Naddoor",
createAddress("Alexandria", "Abu Keer"),
createEmploymentPeriod("03-05-2003", "01-11-2015"),
2000L,
projects);
tx.begin();
em.persist(tamer);
em.persist(nader);
tx.commit();
}
@SuppressWarnings("unchecked")
public List getEmployeeProjects(String employeeName){
return
em.createQuery("select e.projects from Employee e where e.name = :name").
setParameter("name", employeeName).
getResultList();
}
public static void main(String...args){
Controller controller = new Controller();
controller.doTransaction();
for(Project p : controller.getEmployeeProjects("Tamer Al-Tammoor"))
System.out.println(p.getName());
controller.close();
}
}
}}}
The sample tries to persist two employees along with their associated data, then do a simple query to get a list of projects of a specific employee using his/her name. Hibernate does the job of generating and executing the needed DDL against the source database. The following diagram shows the tables generated by hibernate using the annotations of our entity beans:
|>