Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

No Format
borderStylesolid
titlehttp://localhost:8080/ShareHolderWEB/Test
_________________________________________
Looking up ShareHolderBean
Creating ShareAccount 1, Phani, 10
Account is successfully created
Looking up the ShareAccountNumber 1
Printing the details of ShareAccountNumber 1
Account Number = 1
Owner Name = phani
number of shares 10
version=1
_________________________________________

_________________________________________

buying shares 100
Printing the details of ShareAccountNumber 1
Account Number = 1
Owner Name = phani
number of shares 110
version=2
_________________________________________

_________________________________________
selling 50 shares of ShareAccountNumber 1
Printing the details of ShareAccountNumber 1
Account Number = 1
Owner Name = phani
number of shares 60
version=3
_________________________________________

_________________________________________
Printing all the available accounts
*******
Account Number = 1
Owner Name = phani
number of shares 60
version=3
*******
_________________________________________

_________________________________________
Setting the ShareAccount 1 with 500 shares and updating the database
Printing the details of ShareAccountNumber 1
Account Number = 1
Owner Name = phani
number of shares 500
version=0
_________________________________________

_________________________________________
Closing ShareAccountNumber 1
Printing the details of ShareAccountNumber 1
Account Number = 1
Owner Name = null
number of shares 0
version=0
_________________________________________

Inheritance relationship in entities

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

In this technique, a single database table is designated for entire entity class hierarchy exhibiting inheritance relationship. For example, if entity C extends entity B which extends entity A, the fields of all the entities are stored in a single table. The entities A, B and C can be persisted/updated/deleted/retrieved independently. This technique requires all the columns except for primary columns and columns of parent most entity A, should be nullable. This is because, suppose take the case when an entity B is being inserted. The entity B will have the values for the fields of A and itself but no values for fields of C. Since entire hierarchy uses a single table, the columns pertaining to entity C must be nullable. The same case arises when inserting entity A.

The below example illustrates the use this technique. The enterprise application has 3 entities and uses a single database table to store these entities. A stateless session bean uses JPA to perform DML operations on these entities. The web client looks up the SLSB trigger the operations.

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;
 }

}
Note

@DiscriminatorColumn annotation designates table column to be used to discriminate rows that correspond to different entities in the class hierarchy. @DiscriminatorValue annotation provides value that corresponds to the Account entity for the DiscriminatorColumn. The value is Account. Note that the Account entity class is declared as an abstract class. This is to prevent applications from instantiating Account objects. The intention is, to allow instantiating only sub entities SavingsAccount and CurrentAccount as given below.

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;
 }
}
Note

@DiscriminatorValue annotation provides value that corresponds to the SavingsAccount entity for the DiscriminatorColumn. The value is SAVINGSACCOUNT

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;
 }
}
Note

@DiscriminatorValue annotation provides value that corresponds to the SavingsAccount entity for the DiscriminatorColumn. The value is CURRENTACCOUNT.
The CurrentAccount entity has currentAccountRules field and SavingsAccount has SavingsAccountRules field. Both inherit fields from the parent entity Account

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, 
                       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
                      (int accNo, double newBalance);
 public CurrentAccount updateCurrentAccountBalance
                      (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, 
                       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 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 
                            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>Single Table 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 contents of ACCOUNT table in the AccountDB database are as follows.

No Format
borderStylesolid
titleACCOUNT table

ACCOUNTNO ACCOUNTTYPE NAME ADDRESS BRANCHCODE INTERESTRATE MINBALANCE BALANCE CURRENTACCOUNTRULES SAVINGSACCOUNTRULES 
1 CURRENTACCOUNT Joe Joe address 10 20.00 200.00 5000.00 Current Account!!  
2 SAVINGSACCOUNT Joe Joe address 12 234.00 4534.00 13323.00  Savings Account!! 
3 CURRENTACCOUNT John John address 10 20.00 200.00 5000.00 Current Account!!  
4 SAVINGSACCOUNT John John 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.