From scm-return-28373-apmail-geronimo-scm-archive=geronimo.apache.org@geronimo.apache.org Thu May 22 08:21:38 2008 Return-Path: Delivered-To: apmail-geronimo-scm-archive@www.apache.org Received: (qmail 90943 invoked from network); 22 May 2008 08:21:38 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 22 May 2008 08:21:38 -0000 Received: (qmail 56329 invoked by uid 500); 22 May 2008 08:21:39 -0000 Delivered-To: apmail-geronimo-scm-archive@geronimo.apache.org Received: (qmail 56281 invoked by uid 500); 22 May 2008 08:21:39 -0000 Mailing-List: contact scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@geronimo.apache.org List-Id: Delivered-To: mailing list scm@geronimo.apache.org Received: (qmail 56272 invoked by uid 99); 22 May 2008 08:21:39 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 22 May 2008 01:21:39 -0700 X-ASF-Spam-Status: No, hits=-1996.1 required=10.0 tests=ALL_TRUSTED,HTML_MESSAGE,MIME_HTML_ONLY,OBFUSCATING_COMMENT X-Spam-Check-By: apache.org Received: from [140.211.11.140] (HELO brutus.apache.org) (140.211.11.140) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 22 May 2008 08:20:42 +0000 Received: from brutus (localhost [127.0.0.1]) by brutus.apache.org (Postfix) with ESMTP id 0BADE234C118 for ; Thu, 22 May 2008 01:21:00 -0700 (PDT) Message-ID: <2086379053.1211444460026.JavaMail.www-data@brutus> Date: Thu, 22 May 2008 01:21:00 -0700 (PDT) From: confluence@apache.org To: scm@geronimo.apache.org Subject: [CONF] Apache Geronimo v2.1: Java Persistence API deployment plans (page edited) MIME-Version: 1.0 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Virus-Checked: Checked by ClamAV on apache.org

Java Persistence API deployment plans has been edited by Phani Balaji Madgula (May 22, 2008).

=20

(View changes)

Content:

Java Persistence API deployment plans

The Java Persistence API is a new programming model under EJB3.0 specifi= cation (JSR220) for the management of persistence and object/relational map= ping with Java EE and Java SE. With JPA, developers can easily develop java= applications that perform operations on relational database management sys= tems using java objects and mapping. In that way, java applications develop= ed using JPA are not only portable across different platforms, but also app= lications can be easily developed using simple yet powerful programming mod= el provided by JPA. This greatly improves application maintainability again= st ever changing database world. JPA insulates applications from all the co= mplexity and non-portable boilerplate code involved in database connectivit= y and operations.
Apache geronimo uses OpenJPA= 3D""= 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 plans for apache geronimo.

The document is organized as follows.

Sh= areAccount sample

This example illustrates developing an enterprise application that uses = JPA for persistence. The database used is the embedded derby shipped with a= pache geronimo. Here, we present a persistence deployment plan (persist= ence.xml) that contains database connectivity and other information fo= r the application. The persistence.xml is placed under META-IN= F/ directory of the application archive. The application contains an e= jb module and a web module. Ejb module uses a stateless session bean Sh= areHolderBean that uses JPA to perform database operations on the tabl= e SHAREACCOUNT in the ShareDB derby database. The SHA= REACCOUNT table contains information about each shareholder along with= the information regarding number shares he or she possesses currently in t= he account. The ShareHolderBean has methods that retrieve sharehol= der information, buy/sell shares of a particular shareholder, close the sha= reholder account etc. The web application has a servlet that looks up the {= { ShareHolderBean}} and trigger the operations on it. The deployment inform= ation for the ejb module is provided using Java EE annotations in the respe= ctive bean classes. However, the persistence plan is provided using MET= A-INF/persistence.xml file.

sample.jpa.ShareAccount.java
package sample=
.jpa;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.PostLoad;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Version;
import javax.persistence.Table;

@Entity
@Table(name =3D "SHAREACCOUNT")
@NamedQuery(name=3D"findThem", query=3D"SELECT a FROM ShareAccount a")
public class ShareAccount implements Serializable {

  =20
    @Id
    private int shareAccountNo;
    private String ownerName;
    private int numberOfShares;
    @Version
    private int version;

    public ShareAccount(int shareAccountNo,=20
                        String ownerName=
,=20
                        int numberOfShar=
es) {

      this.shareAccountNo =3D shareAcco=
untNo;
      this.ownerName =3D ownerName;
      this.numberOfShares =3D numberOfS=
hares;
       =20
    }

    public =
String toString() {
        return "Acc.# " + shareAccountNo +
               ", owner" + ownerName +=20
               ", numberOfShares: " +=20
                  numberOfShares + " $";
    }

    @PrePersist
    void prepersist() {
        System.out.println("pre persist!!");
    }
   =20
    @PreUpdate
    void preupdate() {
        System.out.println("pre update!!");
    }
   =20
    @PostUpdate
    void postupdate() {
        System.out.println("post update!!");
    }
   =20
    @PostLoad
    void postload() {
        System.out.println("post load!!");
    }

=09public i=
nt getShareAccountNo() {
=09=09return shareAccountNo;
=09}

=09public void setShareAccountNo(int shareAccountNo) {
=09=09this.shareAccountNo =3D shareAcco=
untNo;
=09}

=09public S=
tring getOwnerName() {
=09=09return ownerName;
=09}

=09public void setOwnerName(String ownerName) {
=09=09this.ownerName =3D ownerName;
=09}

=09public i=
nt getNumberOfShares() {
=09=09return numberOfShares;
=09}

=09public void setNumberOfShares(int numberOfShares) {
=09=09this.numberOfShares =3D numberOfS=
hares;
=09}

=09public i=
nt getVersion() {
=09=09return version;
=09}

=09public void setVersion(int version) {
=09=09this.version =3D version;
=09}
 =20
}

Observe various annotations that represent various aspects of the entity= in the class.

@Entity : Marks the ShareAccount class as an entity th= at can be persisted entirely in the database.
@Table(name =3D "SHAREACCOUNT") : Designates the database table SHAREACCOUNT to the entity. The columns in the database table map to= the attributes of ShareAccount entity.
@Id : This annotation designates primary key to the entity. In thi= s case, it is the shareAccountNo attribute of the entity class. @NamedQuery(name=3D"findAccounts", query=3D"SELECT a FROM ShareAccount = a") : This annotation declares a named query by name findAccounts<= /tt>. This query retrieves all the share accounts from the database. Later = in the ShareHolderBean, the NamedQuery is executed by using the na= me findAccounts.
@Version : The version attribute of the ShareAccount enti= ty.

The annotations placed around some of the methods of the ShareAccoun= t class are @PrePersist, @PreUpdate, @PostUpdate and @PostLoad. These are the callback methods called by persistence container when corr= esponding database operations are performed on the entity.

sample.jpa.ShareHolder.java
package sample=
.jpa;
import java.util.List;

public int=
erface ShareHolder {

    public ShareAccount openShareAccoun=
t(int shareHolderNo, String ownerName, int nu=
mberOfShares);
    public ShareAccount findShareAccoun=
t(int shareHolderNo);
    public ShareAccount close(int shareHolderNo);
    public List<ShareAccount> lis=
tAccounts();
    public ShareAccount buyShares(int shareHolderNo, int numberOfShares);
    public =
int sellShares(int shareHolderNo,=
 int numberOfShares);  =20
    public ShareAccount updateShareAcco=
unt(ShareAccount sa);
}

The ShareHolder.java is the remote interface of the stateless s= ession bean.

sample.jpa.ShareHolderBean.jav= a
package sample=
.jpa;
import java.util.List;
import javax.ejb.Stateless;
import javax.ejb.Remote;
import javax.persistence.*;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementT=
ype;

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)=20
@Remote(ShareHolder.class)
public class ShareHolderBean implements ShareHolder {=20
 =20
    @PersistenceContext
    private EntityManager manager;

    public ShareAccount openShareAccoun=
t(int shareHolderNo,=20
                                         String=
 ownerName,=20
                                         int numberOfShares){
    =09
    =09if (findShareAccount(shareHolder=
No) =3D=3D null){
    =09=09ShareAccount sa =3D new Share=
Account
                                 (shareHolderNo,
                                  ownerName,
                                  numberOfShares);
        =09manager.persist(sa);
        =09return sa;
    =09}
    =09return null;
    }

    public ShareAccount findShareAccoun=
t(int shareHolderNo){
    =09ShareAccount sa =3D manager.find(ShareAccount.class,=20
                                       shareHolderNo);
    =09return sa;
    }
   =20
    public ShareAccount close(int shareHolderNo){
    =09ShareAccount sa =3D manager.find(ShareAccount.class,=20
                                       shareHolderNo);  =20
    =09if (sa !=3D null)manager.remove(sa);
    =09return sa;

    }
   =20
    public List<ShareAccount> lis=
tAccounts(){
        Query query =3D manager.createNamedQuery("findThem");
        return query.getResultList();
    }
   =20
    public ShareAccount buyShares(int shareHolderNo,=20
                                  int nu=
mberOfShares){
    =09ShareAccount sa =3D manager.find(ShareAccount.class,=20
                                       shareHolderNo);
    =09if(sa !=3D null){
    =09=09int new_balance =3D sa.getNumb=
erOfShares()=20
                                  + numberOfShares;=20
    =09    sa.setNumberOfShares(new_balance); =20
    =09}
    =09return sa;
    }
   =20
    public =
int sellShares(int shareHolderNo,=
=20
                          int numberOfSh=
ares){
        ShareAccount sa =3D manager.find(ShareAccount.class,=20
                                       shareHolderNo);
        if(sa !=3D null){
            if (numberOfShares > sa.=
getNumberOfShares()){
            =09return -2;
            }else{
            =09int new_balance =3D sa.ge=
tNumberOfShares()=20
                                  - numberOfShares;
            =09sa.setNumberOfShares(new_balance);
            =09manager.flush();
            =09return numberOfShares;
            }
        }else{
        =09return -1;
        }
    }
   =20
    public ShareAccount updateShareAcco=
unt(ShareAccount sa){
    =09ShareAccount sa1 =3D=20
                   findShareAccount(sa.getShareAccountNo());
    =09if (sa1 !=3D null){
    =09=09manager.merge(sa1);
    =09=09return sa1;
    =09}
    =09else return null;
    =09=20
    }

   =20
}

The ShareHolderBean.java is the stateless session bean that use= s JPA to perform database operations using ShareAccount entity.

Persistence.xml
<?xml version=3D"1.0" encoding=3D"UTF=
-8"?>
<persistence xmlns=3D"http://java.sun.com/xml=
/ns/persistence"
  xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance" version=3D"1.0"
  xsi:schemaLocation=3D"http://java.sun.com/xml/ns/persistence=20
  http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

 <persistence-unit name=3D"PersistencePU">
 <description>ShareHolder</description>
 <provider>
  org.apache.openjpa.persistence.PersistenceProviderImpl
 </provider>
 <class>sample.jpa.ShareAccount</class>
 <properties>
  <property name=3D"openjpa.ConnectionURL"=20
           value=3D"jdbc:derby:ShareDB" /=
>
  <property name=3D"openjpa.ConnectionDriverN=
ame"=20
           value=3D"org.apache.derby.jdbc.Embedd=
edDriver" />
  <property name=3D"=
ConnectionUserName" value=3D"app" =
/>
  <property name=3D"=
openjpa.jdbc.SynchronizeMappings" value=3D"false" />
 </properties>
 </persistence-unit>
 <!--
 <jta-data-source>PhoneBookPool</jta-data-source>
 <non-jta-data-source>PhoneBookPool</non-jta-data-source>
 -->
</persistence>

The Persistence.xml is the persistence plan for the ejb module.= It provides database connection information and declares entity classes am= ong other things.

3D""

The default namespace of the above XML document is = http://java.sun.com/xml/ns/persistence3D"". The XML elements that do not have a namespace prefix belong to th= e default namespace.

sample.jpa.Test.java
=
package sample=
.jpa;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRe=
quest;
import javax.servlet.http.HttpServletRe=
sponse;

public class Test extends=20
  javax.servlet.http.HttpServlet=20
  implements javax.servlet.Servlet {
 =20
  static f=
inal long serialVersionUID =3D 1L=
;
  =20
   public Test() {
=09super();
   }   =09
=09
   protected void doGet(HttpServletRequ=
est request,
                  HttpServletResponse response)=20
                  throws ServletExcepti=
on,=20
                  IOException {
=09=09=09=09
    PrintWriter out =3D response.getWriter();
=09       =20
    try {
     java.util.Properties env =3D=20
       new java.util.Properties();

     env.put(Context.INITIAL_CONTEXT_FACTORY
       ,"org.apache.openejb.client.RemoteInitial=
ContextFactory");=20
     env.put(Context.PROVIDER_URL,=20
             "ejbd:=
//127.0.0.1:4201");
=09    =09=09
     Context ctx =3D new InitialContext=
(env);
     out.println("Looking up ShareHolderBean");

     ShareHolder shareHolder =3D (ShareHolder)
            ctx.lookup("ShareHolderBeanRemote");
=09           =20
     out.println("Creating ShareAccount 1,=20
                   Phani, 10");
=09           =20
     ShareAccount sa =3D=20
         shareHolder.openShareAccount(1,"phani"<=
/span>, 10);
     if(sa =3D=3D null){
=09out.println("account could not be created.");
=09out.println("May be, account already=20
                            exists. Check the database.");
           =09
     }
     else {
        out.println("Account is successfully cre=
ated");
     }
     out.println("Looking up the ShareAccountNum=
ber 1");
     sa =3D shareHolder.findShareAccount(1);
     out.println("Printing the details of ShareA=
ccountNumber 1");
     printShareAccount(sa,out);
     out.println("");

     out.println("buying shares 100");
     sa =3D shareHolder.buyShares(1, 100);
=09           =20
     out.println("Printing the details of ShareA=
ccountNumber 1");
     printShareAccount(sa,out);
     out.println("");

     out.println("selling 50 shares of ShareAcco=
untNumber 1");
     int numberShares =3D shareHolder.se=
llShares(1, 50);
     if(numberShares =3D=3D 50){
       out.println("Printing the details of Shar=
eAccountNumber 1");
       sa =3D shareHolder.findShareAccount(1);
       printShareAccount(sa,out);
     }
     else =
if(numberShares =3D=3D -1){
       out.println("ShareAccountNo can not be fo=
und");
     }else {
       out.println("The number shares available =
are less than 50");
     }
     out.println("");

     List<ShareAccount> saList =3D shareHolder.listAccounts();
     out.println("Printing all the available acc=
ounts");
     for (i=
nt i =3D 0; i < saList.size(); i++){
=09=09out.println("*******");
=09=09printShareAccount(saList.get(i),out);
=09=09out.println("*******");
=09=09out.println("");
=09}
     out.println("");

     out.println("Setting the ShareAccount 1 with 500 shares=20
                  and updating the database");
     sa =3D new ShareAccount(1,"phani",0);
     sa.setNumberOfShares(500);
     shareHolder.updateShareAccount(sa);
     out.println("Printing the details of ShareA=
ccountNumber 1");
     printShareAccount(sa,out);
     out.println("");

     out.println("Closing ShareAccountNumber 1"<=
/span>);
     sa =3D shareHolder.close(1);
     if(sa =3D=3D null){
        out.println("Account is not found=3D"+1);
     }else{
        out.println("Printing the details of Sha=
reAccountNumber 1");
=09printShareAccount(sa,out);
     }

   }
   catch(Exception e){
     e.printStackTrace();
     throw new ServletException(e);
   }
}  =09

 protected void doPost(HttpServletReque=
st request,=20
                      HttpServletResponse response)=20
                  throws ServletExcepti=
on, IOException {
=09=09
 } =20
 private void printShareAccount(ShareAc=
count sa, PrintWriter out){
    if(sa !=3D null){
    out.println("Account Number =3D "+sa.getShareAccountNo());
    out.println("Owner Name =3D "+sa.getO=
wnerName());
    out.println("number of shares "+sa.ge=
tNumberOfShares());
    out.println("version=3D"+sa.getVersio=
n());
    }else{
     out.println("ShareAccountNo can not be foun=
d");
    }
 }
}
web.xml
<!--
The deployment descriptor of the web client.
-->
<?xml version=3D"1.0=
" encoding=3D"UTF-8"?>
<web-app xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance"=20
         xmlns=3D"http://java.sun.com/xml/ns/jav=
aee"=20
         xmlns:web=3D"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"=20
         xsi:schemaLocation=3D"http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"=20
         id=3D"WebApp_ID" version=3D"2.5">

  <display-name>ShareHolderWEB</display-name>
   <servlet>
    <description></description>
    <display-name>Test</display-name>
    <servlet-name>Test</servlet-name>
    <servlet-class>sample.jpa.Test</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Test</servlet-name>
    <url-pattern>/Test</url-pattern>
  </servlet-mapping>
</web-app>
geronimo-web.xml
<!--
The geronimo deployment plan of the web client.
-->

<?xml version=3D"1.0=
" encoding=3D"UTF-8"?>
<web-app xmlns=3D"http://geronimo.apache.org/=
xml/ns/j2ee/web-2.0.1"=20
         xmlns:naming=3D"http://geronimo.apache.org/xml/ns/naming-1.2"=20
         xmlns:sec=3D"http://geronimo.apache.org/xml/ns/security-2.0"=20
         xmlns:sys=3D"http://geronimo.apache.org/xml/ns/deployment-1.2">
  <sys:environment>
    <sys:moduleId>
      <sys:groupId>JPA</sys:groupId>
      <sys:artifactId>ShareHolderWEB<=
span class=3D"code-tag"></sys:artifactId>
      <sys:version>1.0</sys:version>
      <sys:type>car</sys:type>
    </sys:moduleId>
  </sys:environment>
  <context-root>/ShareHolderWEB</context-root>
</web-app>

The Servlet client Test.java, looks up the ShareHolderBean<= /tt> and executes various methods on the ShareAccount entity. When= the url http://lo= calhost:8080/ShareHolderWEB/Test3D"" is hit on a browser window, th= e following output is displayed.

_________________________________________
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 =3D 1
Owner Name =3D phani
number of shares 10
version=3D1
_________________________________________

_________________________________________

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

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

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

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

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

Inheritance relationship in entities

Entities can exhibit inheritance relationship among themselves. The enti= ties involved in inheritance relationship can be persisted/updated/retrieve= d independently. There are several ways of realizing inheritance relationsh= ip among entities. There are as follows.

Single database tabl= e per class hierarchy3D""
Separate database table per subcl= ass3D""=
Single data= base table per concrete entity class3D""

Single database table per class hierarchy

In this technique, a single database table is designated for entire enti= ty class hierarchy exhibiting inheritance relationship. For example, if ent= ity C extends entity B which extends entity A, the fields of all the entiti= es are stored in a single table. The entities A, B and C can be persisted/u= pdated/deleted/retrieved independently. This technique requires all the col= umns 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 be= ing inserted. The entity B will have the values for the fields of A and its= elf but no values for fields of C. Since entire hierarchy uses a single tab= le, the columns pertaining to entity C must be nullable. The same case aris= es when inserting entity A.

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

com.sample.jpa.Account
package com.sa=
mple.jpa;

import java.io.Serializable;

import javax.persistence.DiscriminatorC=
olumn;
import javax.persistence.DiscriminatorT=
ype;
import javax.persistence.DiscriminatorV=
alue;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceTyp=
e;
import javax.persistence.Table;

@Entity
@Table(name=3D"Account")
@Inheritance(strategy=3DInheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name=3D"ACCOUNTTYPE"=
,=20
 discriminatorType=3DDiscriminatorType.STRING)
@DiscriminatorValue("ACCOUNT")
public abs=
tract class Account=20
       implements Serializable{
=09
 @Id
 private in=
t accountNo;
 private St=
ring name;
 private St=
ring address;
 private in=
t branchCode;
=09
 public Account(){
  this.accountNo =3D 0;
  this.name =3D "DUMMY";
  this.address =3D "DUMMY";
  this.branchCode =3D 0;
 }
=09
 public int=
 getAccountNo() {
  return accountNo;
 }
 public void setAccountNo(int accountNo) {
  this.accountNo =3D accountNo;
 }
 public Str=
ing getName() {
  return name;
 }
 public void setName(String name) {
  this.name =3D name;
 }
 public Str=
ing getAddress() {
  return address;
 }
 public void setAddress(String address) {
  this.address =3D address;
 }
 public int=
 getBranchCode() {
  return branchCode;
 }
 public void setBranchCode(int branchCode) {
  this.branchCode =3D branchCode;
 }

}
3D""

@DiscriminatorColumn annotation designates table column to be u= sed to discriminate rows that correspond to different entities in the class= hierarchy. @DiscriminatorValue annotation provides value that co= rresponds to the Account entity for the DiscriminatorColumn. The value is Account. Note that the Account entity class is de= clared as an abstract class. This is to prevent applications from instantia= ting Account objects. The intention is, to allow instantiating only sub ent= ities SavingsAccount and CurrentAccount as given below. <= /p>

com.sample.jpa.SavingsAccount<= /b>
package com.sa=
mple.jpa;

import javax.persistence.DiscriminatorC=
olumn;
import javax.persistence.DiscriminatorT=
ype;
import javax.persistence.DiscriminatorV=
alue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceTyp=
e;
import javax.persistence.Table;

@Entity
@Table(name=3D"Account")
@Inheritance(strategy=3DInheritanceType.SINGLE_TABLE)
@DiscriminatorValue("SAVINGSACCOUNT")
public class SavingsAccount extends Account {
 private do=
uble interestRate;
 private do=
uble minBalance;
 private do=
uble balance;
 private St=
ring savingsAccountRules;
=09
 public SavingsAccount(){
  super();
  this.interestRate =3D 0;
  this.minBalance =3D 0;
  this.balance =3D 0;
  this.savingsAccountRules =3D null;
 }
=09
 public dou=
ble getInterestRate() {
  return interestRate;
 }
 public void setInterestRate(double interestRate) {
  this.interestRate =3D interestRate;
 }
 public dou=
ble getMinBalance() {
  return minBalance;
 }
 public void setMinBalance(double minBalance) {
  this.minBalance =3D minBalance;
 }
 public dou=
ble getBalance() {
  return balance;
 }
 public void setBalance(double balance) {
  this.balance =3D balance;
 }
 public Str=
ing getSavingAccountRules() {
  return savingsAccountRules;
 }
 public void setSavingAccountRules(String savingAccountRules) {
  this.savingsAccountRules =3D savingAc=
countRules;
 }
}
3D""

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

com.sample.jpa.CurrentAccount<= /b>
package com.sa=
mple.jpa;

import javax.persistence.DiscriminatorC=
olumn;
import javax.persistence.DiscriminatorT=
ype;
import javax.persistence.DiscriminatorV=
alue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceTyp=
e;
import javax.persistence.Table;

@Entity
@Table(name=3D"Account")
@Inheritance(strategy=3DInheritanceType.SINGLE_TABLE)
@DiscriminatorValue("CURRENTACCOUNT")
public class CurrentAccount extends Account {
 private do=
uble interestRate;
 private do=
uble minBalance;
 private do=
uble balance;
 private St=
ring currentAccountRules;
=09
 public CurrentAccount(){
  super();
  this.interestRate =3D 0;
  this.minBalance =3D 0;
  this.balance =3D 0;
  this.currentAccountRules =3D null;
 }
 public dou=
ble getInterestRate() {
  return interestRate;
 }
 public void setInterestRate(double interestRate) {
  this.interestRate =3D interestRate;
 }
 public dou=
ble getMinBalance() {
  return minBalance;
 }
 public void setMinBalance(double minBalance) {
  this.minBalance =3D minBalance;
 }
 public dou=
ble getBalance() {
  return balance;
 }
 public void setBalance(double balance) {
  this.balance =3D balance;
 }
 public Str=
ing getCurrentAccountRules() {
  return currentAccountRules;
 }
 public void setCurrentAccountRules(String currentAccountRules) {
  this.currentAccountRules =3D currentA=
ccountRules;
 }
}
3D""

@DiscriminatorValue annotation provides value that corresponds = to the SavingsAccount entity for the DiscriminatorColumn.= The value is CURRENTACCOUNT.
The CurrentAccount entity has currentAccountRules field a= nd SavingsAccount has SavingsAccountRules field. Both inh= erit fields from the parent entity Account

com.sample.jpa.AccessAccountSt= ateless
package com.sa=
mple.jpa;
import java.util.List;
public int=
erface AccessAccountStateless {
 public SavingsAccount createSavingsAcc=
ount
                      (int accNo, String name,=20
                       String address, <=
span class=3D"code-object">int branchCode,
=09=09       double interestRate,
                       double minBalance=
,
=09=09       double balance,=20
                       String savingsAcc=
ountRules);
=09
 public CurrentAccount createCurrentAcc=
ount
                      (int accNo, String name,
=09=09       String address, int branchCode,
=09=09       double interestRate,=20
                       double minBalance=
,
=09=09       double balance,=20
                       String currentAcc=
ountRules);
 public List listAccounts();
 public SavingsAccount updateSavingsAcc=
ountBalance
                      (int accNo, double newBalance);
 public CurrentAccount updateCurrentAcc=
ountBalance
                      (int accNo, double newBalance);
 public void deleteSavingsAccount(int accNo);
 public void deleteCurrentAccount(int accNo);
}
com.sample.jpa.AccessAccountSt= atelessBean
package com.sa=
mple.jpa;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceCon=
text;
import javax.persistence.Query;


@Stateless
@Remote
public class AccessAccountStatelessBean=
=20
             implements AccessAccountSt=
ateless{
 @PersistenceContext(unitName=3D"SingleTableInhe=
ritance")
  EntityManager em;
=09
 public SavingsAccount createSavingsAcc=
ount
                      (int accNo, String name,=20
=09=09       String address, int branchCode,
=09=09       double interestRate,=20
                       double minBalance=
,
=09=09       double balance,=20
                       String savingsAcc=
ountRules){
=09=09
  SavingsAccount sa =3D new SavingsAcco=
unt();
  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 createCurrentAcc=
ount
                      (int accNo, String name,=20
=09=09       String address, int branchCode,
=09=09       double interestRate,=20
                       double minBalance=
,
=09=09       double balance,=20
                       String currentAcc=
ountRules){

  CurrentAccount ca =3D new CurrentAcco=
unt();
  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 =3D new ArrayList();
  Query q1 =3D em.createQuery("SELECT sa FROM Sa=
vingsAccount sa");
  List currList1 =3D q1.getResultList();
  allList.addAll(currList1);
  Query q2 =3D em.createQuery("SELECT ca FROM Cu=
rrentAccount ca");
  List currList2 =3D q2.getResultList();
  allList.addAll(currList2);
  return allList;
 }

 public SavingsAccount updateSavingsAcc=
ountBalance
                      (int accNo, double newBalance){
  SavingsAccount sa =3D em.find(SavingsAccount.class, accNo);
  if (sa =3D=3D null)=20
     throw new IllegalStateException("Account numbe=
r not found");
  Query q =3D em.createQuery("UPDATE SavingsAccount sa SET=20
                            sa.balance =3D "+newBalance);
  q.executeUpdate();
  return sa;
=09=09=20
 }
 public CurrentAccount updateCurrentAcc=
ountBalance
                      (int accNo, double newBalance){
  CurrentAccount ca =3D em.find(CurrentAccount.class, accNo);
  if (ca =3D=3D null) throw new IllegalStateException
                 ("Account number not found");
  Query q =3D em.createQuery("UPDATE CurrentAccount=20
                            ca SET ca.balance =3D "+newBalance);
  q.executeUpdate();
  return ca;
 }

 public void deleteSavingsAccount(int accNo){
  SavingsAccount sa =3D em.find(SavingsAccount.class, accNo);
  if(sa =3D=3D null)=20
     throw new IllegalStateException("Account numbe=
r not found");
  em.remove(sa);
 }
 public void deleteCurrentAccount(int accNo){
  CurrentAccount ca =3D em.find(CurrentAccount.class, accNo);
  if(ca =3D=3D null)=20
   throw n=
ew IllegalStateException("Account number =
not found");
  em.remove(ca);
 }
}
com.sample.jpa.Test
<= div class=3D"codeContent">
package com.sa=
mple.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.HttpServletRe=
quest;
import javax.servlet.http.HttpServletRe=
sponse;

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

 static fi=
nal long serialVersionUID =3D 1L;
 @EJB AccessAccountStateless aas;

 public Test() {
  super();
 }   =09
 protected void doGet(HttpServletReques=
t request,=20
                      HttpServletResponse response)=20
                      throws ServletExc=
eption,=20
                      IOException {
  PrintWriter out =3D response.getWriter();
  int accNo =3D Integer.parseInt(request.getParameter("accNo"));
  String name =3D request.getParameter(<=
span class=3D"code-quote">"name");

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

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

  out.println("Created a Savings account=20
               and a Current Account");
  List accList =3D 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&=
gt;");
  out.println("<th>Balance</th>");
  out.println("<th>Current Account Rules&l=
t;/th>");
  out.println("<th>Savings Account Rules&l=
t;/th>");
  out.println("</tr>");

  for(int i =3D 0; i < accList.size(); i++){
   Account a =3D (Account)accList.get(i);
   if (a i=
nstanceof SavingsAccount){
    SavingsAccount sa =3D (SavingsAccount)a;
    out.println("<tr>");
    out.println("<td>"+sa.getAccoun=
tNo()+"</td>");
    out.println("<td>"+sa.getName()=
+"</td>");
    out.println("<td>"+sa.getAddres=
s()+"</td>");
    out.println("<td>"+sa.getBranch=
Code()+"</td>");
    out.println("<td>"+sa.getIntere=
stRate()+"</td>");
    out.println("<td>"+sa.getMinBal=
ance()+"</td>");
    out.println("<td>"+sa.getBalanc=
e()+"</td>");
    out.println("<td></td>");
    out.println("<td>"+sa.getSaving=
AccountRules()+"</td>");
    out.println("</tr>");
   }else i=
f (a instanceof CurrentAccount){
    CurrentAccount ca =3D (CurrentAccount)a;
    out.println("<tr>");
    out.println("<td>"+ca.getAccoun=
tNo()+"</td>");
    out.println("<td>"+ca.getName()=
+"</td>");
    out.println("<td>"+ca.getAddres=
s()+"</td>");
    out.println("<td>"+ca.getBranch=
Code()+"</td>");
    out.println("<td>"+ca.getIntere=
stRate()+"</td>");
    out.println("<td>"+ca.getMinBal=
ance()+"</td>");
    out.println("<td>"+ca.getBalanc=
e()+"</td>");
    out.println("<td>"+ca.getCurren=
tAccountRules()+"</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..!!");
 }  =09
=09
 protected void doPost(HttpServletReque=
st request,=20
                       HttpServletResponse response)=20
                       throws ServletEx=
ception,=20
                              IOException {
 }   =09  =09   =20
}

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

Persistence.xml
<?xml version=3D"1.0" encoding=3D"UTF=
-8"?>
<persistence=20
 xmlns=3D"http://java.sun.com/xml/ns/persistence=
"
 xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance"=20
 version=3D"1.0"
 xsi:schemaLocation=3D"http://java.sun.com/xml/ns/persistence
 http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
=20
 <persistence-unit name=3D"SingleTableInheritance">
 <description>Single Table Inheritanc=
e 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=20
   name=3D"openjpa.ConnectionURL"=20
   value=3D"jdbc:derby:AccountDB" />
  <property=20
   name=3D"openjpa.ConnectionDriverName"=
=20
   value=3D"org.apache.derby.jdbc.EmbeddedDriver=
" />
   <property name=3D=
"ConnectionUserName" value=3D"app"=
 />
   <property name=3D"openjpa.jdbc.Synchronize=
Mappings"=20
    value=3D"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 declar= es the entities in the persistence unit as well. The following procedure ex= plains how to deploy/run the sample.

*Create an EAR application that contains an EJB application packaging al= l entity classes, ejb classes and META-INF/persistence.xml
*Create META-INF/ejb-jar.xml. Since we have used annotations, we do not hav= e 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.

ACCOUNT table
create table ACCOUNT(ACCOUNTNO integer, ACCOUNTTYPE=
 varchar(50), NAME varchar(50), ADDRESS varchar(225), BRANCHCODE integer, I=
NTERESTRATE 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 databas= e are as follows.

ACCOUNT table<= /b>
ACCOUNTNO ACCOUNTTYPE NAME ADDRESS BRANCHCODE INTERESTRATE MINBALANCE =
BALANCE CURRENTACCOUNTRULES SAVINGSACCOUNTRULES=20
1 CURRENTACCOUNT Joe Joe address 10 20.00 200.00 5000.00 Current Account!! =
=20
2 SAVINGSACCOUNT Joe Joe address 12 234.00 4534.00 13323.00  Savings Accoun=
t!!=20
3 CURRENTACCOUNT John John address 10 20.00 200.00 5000.00 Current Account!=
! =20
4 SAVINGSACCOUNT John John address 12 234.00 4534.00 13323.00  Savings Acco=
unt!!

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