Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin
Wiki Markup
{scrollbar}

Java Persistence API

...

The Java Persistence API is a new programming model under EJB3.0 specification (JSR220) for the management of persistence and object/relational mapping with Java EE and Java SE. With JPA, developers can easily develop java applications that perform operations on relational database management systems using java objects and mapping. In that way, java applications developed using JPA are not only portable across different platforms, but also applications can be easily developed using simple yet powerful programming model provided by JPA. This greatly improves application maintainability against ever changing database world. JPA insulates applications from all the complexity and non-portable boilerplate code involved in database connectivity and operations.
Apache geronimo uses OpenJPA for providing Java Persistence API to Java EE applications deployed in the server. Below sections illustrate developing applications using JPA and how to write various deployment descriptors and plans for apache geronimo.

...

This example illustrates developing an enterprise application that uses JPA for persistence. The database used is the embedded derby shipped with apache geronimo. Here, we present a persistence deployment plan descriptor (persistence.xml) that contains database connectivity and other information for the application. The persistence.xml is placed under META-INF/ directory of the application archive. The application contains an ejb module and a web module. Ejb module uses a stateless session bean ShareHolderBean that uses JPA to perform database operations on the table SHAREACCOUNT in the ShareDB derby database. The SHAREACCOUNT table contains information about each shareholder along with the information regarding number shares he or she possesses currently in the account. The ShareHolderBean has methods that retrieve shareholder information, buy/sell shares of a particular shareholder, close the shareholder account etc. The web application has a servlet that looks up the {{ ShareHolderBean}} and trigger the operations on it. The deployment descriptor information for the ejb module is provided using Java EE annotations in the respective bean classes. However, the persistence plan deployment descriptor information is provided using META-INF/persistence.xml file.

...

The Persistence.xml is the persistence plan deployment descriptor for the ejb module. It provides database connection information and declares entity classes among other things.

Note

The default namespace of the above XML document is http://java.sun.com/xml/ns/persistenceImage Removed. The XML elements that do not have a namespace prefix belong to the default namespace.

...

The Servlet client Test.java, looks up the ShareHolderBean and executes various methods on the ShareAccount entity. When the url http://localhost:8080/ShareHolderWEB/TestImage Removed is hit on a browser window, the following output is displayed.

...

Entities can exhibit inheritance relationship among themselves. The entities involved in inheritance relationship can be persisted/updated/retrieved independently. There are several ways of realizing inheritance relationship among entities. There are as follows.

  • Single database table per class hierarchy
  • Separate database table per subclass
  • Single database table per concrete entity class

Single database table per class hierarchy

...

Code Block
JAVA
JAVA
borderStylesolid
titlecom.sample.jpa.Account
package com.sample.jpa;

import java.io.Serializable;

import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Table(name="Account")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="ACCOUNTTYPE", 
 discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue("ACCOUNT")
public abstract class Account 
       implements Serializable{
	
 @Id
 private int accountNo;
 private String name;
 private String address;
 private int branchCode;
	
 public Account(){
  this.accountNo = 0;
  this.name = "DUMMY";
  this.address = "DUMMY";
  this.branchCode = 0;
 }
	
 public int getAccountNo() {
  return accountNo;
 }
 public void setAccountNo(int accountNo) {
  this.accountNo = accountNo;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getAddress() {
  return address;
 }
 public void setAddress(String address) {
  this.address = address;
 }
 public int getBranchCode() {
  return branchCode;
 }
 public void setBranchCode(int branchCode) {
  this.branchCode = branchCode;
 }

}

...

Code Block
JAVA
JAVA
borderStylesolid
titlecom.sample.jpa.SavingsAccount
package com.sample.jpa;

import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Table(name="Account")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorValue("SAVINGSACCOUNT")
public class SavingsAccount extends Account {
 private double interestRate;
 private double minBalance;
 private double balance;
 private String savingsAccountRules;
	
 public SavingsAccount(){
  super();
  this.interestRate = 0;
  this.minBalance = 0;
  this.balance = 0;
  this.savingsAccountRules = null;
 }
	
 public double getInterestRate() {
  return interestRate;
 }
 public void setInterestRate(double interestRate) {
  this.interestRate = interestRate;
 }
 public double getMinBalance() {
  return minBalance;
 }
 public void setMinBalance(double minBalance) {
  this.minBalance = minBalance;
 }
 public double getBalance() {
  return balance;
 }
 public void setBalance(double balance) {
  this.balance = balance;
 }
 public String getSavingAccountRules() {
  return savingsAccountRules;
 }
 public void setSavingAccountRules(String savingAccountRules) {
  this.savingsAccountRules = savingAccountRules;
 }
}

...

Code Block
JAVA
JAVA
borderStylesolid
titlecom.sample.jpa.CurrentAccount
package com.sample.jpa;

import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Table(name="Account")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorValue("CURRENTACCOUNT")
public class CurrentAccount extends Account {
 private double interestRate;
 private double minBalance;
 private double balance;
 private String currentAccountRules;
	
 public CurrentAccount(){
  super();
  this.interestRate = 0;
  this.minBalance = 0;
  this.balance = 0;
  this.currentAccountRules = null;
 }
 public double getInterestRate() {
  return interestRate;
 }
 public void setInterestRate(double interestRate) {
  this.interestRate = interestRate;
 }
 public double getMinBalance() {
  return minBalance;
 }
 public void setMinBalance(double minBalance) {
  this.minBalance = minBalance;
 }
 public double getBalance() {
  return balance;
 }
 public void setBalance(double balance) {
  this.balance = balance;
 }
 public String getCurrentAccountRules() {
  return currentAccountRules;
 }
 public void setCurrentAccountRules
          (String currentAccountRules) {
  this.currentAccountRules = currentAccountRules;
 }
}

...

Code Block
JAVA
JAVA
borderStylesolid
titlecom.sample.jpa.AccessAccountStateless
package com.sample.jpa;
import java.util.List;
public interface AccessAccountStateless {
 public SavingsAccount createSavingsAccount
                      (int accNo, String name, 
                       String address, int branchCode,
		       double interestRate,
         double minBalance,
	 double balance, 
          double minBalance,String savingsAccountRules);
		
 public CurrentAccount createCurrentAccount
    double balance, 
                       String savingsAccountRules);
	
 public CurrentAccount createCurrentAccount
                      (int accNo, String name,
		       String address, int branchCode,
		        double interestRate, 
                       double minBalance,
		       double balance, 
                       String currentAccountRules);
 public List listAccounts();
 public SavingsAccount updateSavingsAccountBalance
        updateSavingsAccountBalance
       (int accNo,  
      (int accNo, double newBalance);
 public CurrentAccount updateCurrentAccountBalance
        updateCurrentAccountBalance
       (int accNo, 
      (int accNo, double newBalance);
 public void deleteSavingsAccount(int accNo);
 public void deleteCurrentAccount(int accNo);
}
Code Block
JAVA
JAVA
borderStylesolid
titlecom.sample.jpa.AccessAccountStatelessBean
package com.sample.jpa;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;


@Stateless
@Remote
public class AccessAccountStatelessBean 
             implements AccessAccountStateless{
 @PersistenceContext(unitName="SingleTableInheritance")
  EntityManager em;
	
 public SavingsAccount createSavingsAccount
                      (int accNo, String name, 
		       String address, int branchCode,
		       double interestRate, 
            EntityManager em;
	
 public SavingsAccount createSavingsAccount
       (int accNo, String name, 
	String address, doubleint minBalancebranchCode,
		       double balanceinterestRate, 
        double minBalance,
	double balance,   
          String savingsAccountRules){
		
  SavingsAccount sa = new SavingsAccount();
  sa.setAccountNo(accNo);
  sa.setAddress(address);
  sa.setBalance(balance);
  sa.setBranchCode(branchCode);
  sa.setMinBalance(minBalance);
  sa.setName(name);
  sa.setSavingAccountRules(savingsAccountRules);
  sa.setInterestRate(interestRate);
  em.persist(sa);
  return sa;
 }

 public CurrentAccount createCurrentAccount
                      (int accNo, String name, 
		       String address, int branchCode,
		       double interestRate, 
                       double minBalance,
		       double balanceinterestRate, 
        double minBalance,
	double balance, 
            String currentAccountRules){

  CurrentAccount ca = new CurrentAccount();
  ca.setAccountNo(accNo);
  ca.setAddress(address);
  ca.setBalance(balance);
  ca.setCurrentAccountRules(currentAccountRules);
  ca.setInterestRate(interestRate);
  ca.setMinBalance(minBalance);
  ca.setName(name);
  ca.setBranchCode(branchCode);
  em.persist(ca);
  return ca;
 }

 public List listAccounts(){
  List allList = new ArrayList();
  Query q1 = em.createQuery("SELECT sa FROM SavingsAccount sa");
  List currList1 = q1.getResultList();
  allList.addAll(currList1);
  Query q2 = em.createQuery("SELECT ca FROM CurrentAccount ca");
  List currList2 = q2.getResultList();
  allList.addAll(currList2);
  return allList;
 }

 public SavingsAccount updateSavingsAccountBalance
                      (int accNo, double newBalance){
  SavingsAccount sa = 
   em.find(SavingsAccount.class, accNo);
  if (sa == null) 
     throw new IllegalStateException
          ("Account number not found");
  Query q = em.createQuery("UPDATE SavingsAccount sa SET 
       ("UPDATE SavingsAccount sa SET     
             sa.balance = "+newBalance);
  q.executeUpdate();
  return sa;
		 
 }
 public CurrentAccount updateCurrentAccountBalance
                      (int accNo, double newBalance){
  CurrentAccount ca = em.find(CurrentAccount.class, accNo);
  if (ca == null) throw new IllegalStateException
                 ("Account number not found");
  Query q = em.createQuery("UPDATE CurrentAccount 
                            ca SET ca.balance = "+newBalance);
  q.executeUpdate();
  return ca;
 }

 public void deleteSavingsAccount(int accNo){
  SavingsAccount sa = 
   em.find(SavingsAccount.class, accNo);
  if(sa == null) 
     throw new 
      IllegalStateException("Account number not found");
  em.remove(sa);
 }
 public void deleteCurrentAccount(int accNo){
  CurrentAccount ca = 
   em.find(CurrentAccount.class, accNo);
  if(ca == null) 
   throw new IllegalStateException
    ("Account number not found");
  em.remove(ca);
 }
}
Code Block
JAVA
JAVA
borderStylesolid
titlecom.sample.jpa.Test
package com.sample.jpa;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Test extends 
 javax.servlet.http.HttpServlet 
 implements javax.servlet.Servlet {

 static final long serialVersionUID = 1L;
 @EJB AccessAccountStateless aas;

 public Test() {
  super();
 }   	
 protected void doGet(HttpServletRequest request, 
                      HttpServletResponse response) 
                      throws ServletException, 
                      IOException {
  PrintWriter out = response.getWriter();
  int accNo = Integer.parseInt(request.getParameter("accNo"));
  String name = request.getParameter("name");

  aas.createCurrentAccount(accNo, name, 
      name+"' address", 10, 20, 200, 5000, 
      "Current Account!!");

  aas.createSavingsAccount(accNo+1, name, 
      name+"' address",	12, 234, 4534, 13323, 
      "Savings Account!!");

  out.println("Created a Savings account 
               and a Current Account");
  List accList = aas.listAccounts();
  out.println("<table>");
  out.println("<tr>");
  out.println("<th>AccountNumber</th>");
  out.println("<th>Name</th>");
  out.println("<th>Address</th>");
  out.println("<th>Branch Code</th>");
  out.println("<th>Interest Rate</th>");
  out.println("<th>Minimum Balance</th>");
  out.println("<th>Balance</th>");
  out.println("<th>Current Account Rules</th>");
  out.println("<th>Savings Account Rules</th>");
  out.println("</tr>");

  for(int i = 0; i < accList.size(); i++){
   Account a = (Account)accList.get(i);
   if (a instanceof SavingsAccount){
    SavingsAccount sa = (SavingsAccount)a;
    out.println("<tr>");
    out.println("<td>"+sa.getAccountNo()+"</td>");
    out.println("<td>"+sa.getName()+"</td>");
    out.println("<td>"+sa.getAddress()+"</td>");
    out.println("<td>"+sa.getBranchCode()+"</td>");
    out.println("<td>"+sa.getInterestRate()+"</td>");
    out.println("<td>"+sa.getMinBalance()+"</td>");
    out.println("<td>"+sa.getBalance()+"</td>");
    out.println("<td></td>");
    out.println("<td>"+sa.getSavingAccountRules()+"</td>");
    out.println("</tr>");
   }else if (a instanceof CurrentAccount){
    CurrentAccount ca = (CurrentAccount)a;
    out.println("<tr>");
    out.println("<td>"+ca.getAccountNo()+"</td>");
    out.println("<td>"+ca.getName()+"</td>");
    out.println("<td>"+ca.getAddress()+"</td>");
    out.println("<td>"+ca.getBranchCode()+"</td>");
    out.println("<td>"+ca.getInterestRate()+"</td>");
    out.println("<td>"+ca.getMinBalance()+"</td>");
    out.println("<td>"+ca.getBalance()+"</td>");
    out.println("<td>"+ca.getCurrentAccountRules()+"</td>");
    out.println("<td></td>");
    out.println("</tr>");
   }
  }
  out.println("</table>");
  out.println("Deleting both the accounts "+accNo+" and "+(accNo+1));
  //aas.deleteCurrentAccount(accNo);
  //aas.deleteSavingsAccount(accNo+1);
  //out.println("Accounts successfully deleted..!!");
 }  	
	
 protected void doPost(HttpServletRequest request, 
                       HttpServletResponse response) 
                       throws ServletException, 
                              IOException {
 }   	  	    
}

The above servlet client only inserts entities in the table ACCOUNT. The code that deletes entities is commented out. We can write variety of clients that lookup the EJB and perform operations on the entities.

Code Block
XML
XML
borderStylesolid
titlePersistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence 
 xmlns="http://java.sun.com/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 version="1.0"
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
 http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
 
 <persistence-unit name="SingleTableInheritance">
 <description>
   <description>SingleSingle Table Inheritance example<Inheritance example
 </description>
 <provider>
  org.apache.openjpa.persistence.PersistenceProviderImpl
 </provider>
 <class>com.sample.jpa.Account</class>
 <class>com.sample.jpa.SavingsAccount</class>
 <class>com.sample.jpa.CurrentAccount</class>
 <properties>
  <property 
   name="openjpa.ConnectionURL" 
   value="jdbc:derby:AccountDB" />
  <property 
   name="openjpa.ConnectionDriverName" 
   value="org.apache.derby.jdbc.EmbeddedDriver" />
   <property name="ConnectionUserName" value="app" />
   <property name="openjpa.jdbc.SynchronizeMappings" 
    value="false" />
  </properties>
 </persistence-unit>
 <!--
 <jta-data-source>PhoneBookPool</jta-data-source>
 <non-jta-data-source>PhoneBookPool</non-jta-data-source>
 -->
</persistence>

The persistence schema uses AccountDB derby database. It declares the entities in the persistence unit as well. The following procedure explains how to deploy/run the sample.*

  • Create an EAR application that contains an EJB application packaging all entity classes, ejb classes and META-INF/persistence.xml

...

  • Create META-INF/ejb-jar.xml. Since we have used annotations, we do not have to provide any declarations in it.

...

  • Create a WEB application in the EAR and add the above servlet.

...

  • Create a derby database by name AccountDB using admin console.

...

  • Create a table by name ACCOUNT as following.
    Code Block
    SQL
    SQL
    borderStylesolid
    titleACCOUNT table
    
    create table ACCOUNT(ACCOUNTNO integer, 
                 ACCOUNTTYPE varchar(50), 
                 NAME varchar(50), 
                 ADDRESS varchar(225),
                 BRANCHCODE integer, 
                 INTERESTRATE decimal(15,2)

...

  • , 
                 MINBALANCE decimal(15,2), 
                 BALANCE decimal(15,2), 
                 CURRENTACCOUNTRULES varchar(225), 
                 SAVINGSACCOUNTRULES varchar(225))
    

...

  • The following data will be inserted into ACCOUNT table.
    No Format
    borderStylesolid
    titleACCOUNT table
    
    ACCOUNTNO ACCOUNTTYPE NAME ADDRESS BRANCHCODE INTERESTRATE MINBALANCE BALANCE CURRENTACCOUNTRULES SAVINGSACCOUNTRULES 
    1 CURRENTACCOUNT Joe Joe's address 10 20.00 200.00 5000.00 Current Account!!  
    2 SAVINGSACCOUNT Joe Joe's address 12 234.00 4534.00 13323.00  Savings Account!! 
    3 CURRENTACCOUNT John John's address 10 20.00 200.00 5000.00 Current Account!!  
    4 SAVINGSACCOUNT John John's address 12 234.00 4534.00 13323.00  Savings Account!!
    

Note that JPA has inserted the value CURRENTACCOUNT in the column ACCOUNTTYPE for CurrentAccount entities and inserted the value {SAVINGSACCOUNT}} for SavingsAccount entites.