EJB Programmer's Guide: Developing Entity Beans

Target Audience and Content

The target audience for this guide is the Enterprise Bean provider, i.e. the person in charge of developing the software components on the server side, and more specifically the Entity Beans.

The content of this guide is the following:

  1. Target Audience and content
  2. Introduction
  3. The Home Interface
  4. The Component Interface
  5. The Primary Key Class
  6. The Enterprise Bean Class
  7. Writing Database Access Operations (bean-managed persistence)
  8. Configuring Database Access for Container-managed Persistence
  9. Tuning Container for Entity Bean Optimizations
  10. Using CMP2.0 Persistence

Introduction

An Entity Bean is comprised of the following elements, which are developed by the Enterprise Bean Provider: Note that, according to the EJB 2.0 specification, the couple "Component Interface and Home Interface" can be either local or remote. Local Interfaces (Home and Component) are to be used by a client running in the same JVM as the EJB component. Create and finder methods of a local (or remote) home interface return local (or remote) component interfaces. An EJB component may have both remote and local interfaces, even if normally only one type of interface is provided. If an entity bean is the target of a container-managed relationship (refer to EJB 2.0 persistence), then it must have local interfaces.

The description of these elements is provided in the following sections.

Note that in this documentation, the term "Bean" always means "Enterprise Bean."

An entity bean represents persistent data. It is an object view of an entity stored in a relational database. The persistence of an entity bean can be handled in two ways:

Currently, the platform handles persistence in relational storage systems through the JDBC interface. For both container-managed and bean-managed persistence, JDBC connections are obtained from an object provided at the EJB server level, the DataSource. The DataSource interface is defined in the JDBC 2.0 standard extensions. A DataSource object identifies a database and a means to access it via JDBC (a JDBC driver). An EJB server may propose access to several databases and thus provides the corresponding DataSource objects. DataSources are described in more detail in the section "Configuring JDBC DataSources."

The Home Interface

In addition to "home business methods," the Home interface is used by any client application to create, remove, and retrieve instances of the entity bean. The bean provider only needs to provide the desired interface; the container will automatically provide the implementation. The interface must extend the javax.ejb.EJBHome interface if it is remote, or the javax.ejb.EJBLocalHome interface if it is local. The methods of a remote home interface must follow the rules for java RMI. The signatures of the "create" and "find..." methods should match the signatures of the "ejbCreate" and "ejbFind..." methods that will be provided later in the enterprise bean implementation class (same number and types of arguments, but different return types).

create methods:

remove methods: finder methods:

Finder methods are used to search for an EJB object or a collection of EJB objects. The arguments of the method are used by the entity bean implementation to locate the requested entity objects. For bean-managed persistence, the bean provider is responsible for developing the corresponding ejbFinder methods in the bean implementation. For container-managed persistence, the bean provider does not write these methods; they are generated at deployment time by the platform tools; the description of the method is provided in the deployment descriptor, as defined in the section "Configuring database access for container-managed persistence." In the Home interface, the finder methods must adhere to the following rules:

At least one of these methods is mandatory: findByPrimaryKey, which takes as argument a primary key value and returns the corresponding EJB object.

home methods:

Example

The Account bean example, provided with the platform examples, is used to illustrate these concepts. The state of an entity bean instance is stored in a relational database, where the following table should exist, if CMP 1.1 is used:

create table ACCOUNT (ACCNO integer primary key, CUSTOMER varchar(30), BALANCE number(15,4));

public interface AccountHome extends EJBHome {

    public Account create(int accno, String customer, double balance)
        throws RemoteException, CreateException;

    public Account findByPrimaryKey(Integer pk)
        throws RemoteException, FinderException;

    public Account findByNumber(int accno)
        throws RemoteException, FinderException;

    public Enumeration findLargeAccounts(double val)
        throws RemoteException, FinderException;
}

The Component Interface

Business methods:

The Component Interface is the client's view of an instance of the entity bean. It is what is returned to the client by the Home interface after creating or finding an entity bean instance. This interface contains the business methods of the enterprise bean. The interface must extend the javax.ejb.EJBObject interface if it is remote, or the javax.ejb.EJBLocalObject if it is local. The methods of a remote component interface must follow the rules for java RMI. For each method defined in this component interface, there must be a matching method of the bean implementation class (same arguments number and types, same return type, same exceptions except for RemoteException).

Example

public interface Account extends EJBObject {
    public double getBalance() throws RemoteException;
    public void setBalance(double d) throws RemoteException;
    public String getCustomer() throws RemoteException;
    public void setCustomer(String c) throws RemoteException;
    public int getNumber() throws RemoteException;
}

The Primary Key Class

The Primary Key class is necessary for entity beans only. It encapsulates the fields representing the primary key of an entity bean in a single object. If the primary key in the database table is composed of a single column with a basic data type, the simplest way to define the primary key in the bean is to use a standard java class (for example, java.lang.Integer or java.lang.String). This must have the same type as a field in the bean class. It is not possible to define it as a primitive field (for example, int, float or boolean). Then, it is only necessary to specify the type of the primary key in the deployment descriptor:
      <prim-key-class>java.lang.Integer</prim-key-class>
And, for container-managed persistence, the field which represents the primary key:
      <primkey-field>accno</primkey-field>
The alternative way is to define its own Primary Key class, described as follows:

The class must be serializable and must provide suitable implementation of the hashcode() and equals(Object) methods.

For container-managed persistence, the following rules must be followed:

Example

public class AccountBeanPK implements java.io.Serializable {
public int accno;

public AccountBeanPK(int accno) { this.accno = accno; }

public AccountBeanPK() { }

public int hashcode() { return accno; }
public boolean equals(Object other) {
...
}
}

Special case: Automatic generation of primary keys field

For a CMP 2.0 and CMP1 entity bean, the automatic primary key field can be used by simply declaring the primary-key-class to java.lang.Object. The container will create an internal CMP field and generate its value when the entity bean is created. For CMP2 legacy and CMP1, the specific <automatic-pk-field-name> tag can be used to specify the name of the internal CMP field.

Example of using the new element:

JOnAS specific deployment descriptor:
<jonas-ejb-jar xmlns="http://www.objectweb.org/jonas/ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.objectweb.org/jonas/ns http://www.objectweb.org/jonas/ns/jonas-ejb-jar_4_0.xsd" >
 <jonas-entity>
    <ejb-name>AddressEJB</ejb-name>
    <jdbc-mapping>
        <jndi-name>jdbc_1</jndi-name>
        <automatic-pk-field-name>FieldPkAuto</automatic-pk-field-name>
    </jdbc-mapping>
 </jonas-entity>

Standard deployment descriptor:
  <entity>
      <ejb-name>AddressEJB</ejb-name>
      <local-home>com.titan.address.AddressHomeLocal</local-home>
      <local>com.titan.address.AddressLocal</local>
      <ejb-class>com.titan.address.AddressBean</ejb-class>
      <persistence-type>Container</persistence-type>
      <prim-key-class>java.lang.Object</prim-key-class>
      <reentrant>False</reentrant>
      <cmp-version>2.x</cmp-version>
      <abstract-schema-name>Cmp2_Address</abstract-schema-name>
      <cmp-field><field-name>street</field-name></cmp-field>
      <cmp-field><field-name>city</field-name></cmp-field>
      <cmp-field><field-name>state</field-name></cmp-field>
      <cmp-field><field-name>zip</field-name></cmp-field>

Address Bean Class:
   //  Primary key is not explicitly initialized during ejbCreate method
   public Integer ejbCreateAddress(String street, String city, String state,  String zip ) throws javax.ejb.CreateException {
       setStreet(street);
       setCity(city);
       setState(state);
       setZip(zip);
       return null;
    }

Old specific tag name <automatic-pk> is deprecated in JOnAS 4.0+.

The Enterprise Bean Class

The EJB implementation class implements the bean's business methods of the component interface and the methods dedicated to the EJB environment, the interface of which is explicitly defined in the EJB specification. The class must implement the javax.ejb.EntityBean interface, must be defined as public, cannot be abstract for CMP 1.1, and must be abstract for CMP 2.0 (in this case, the abstract methods are the get and set accessor methods of the bean cmp and cmr fields). Following is a list of the EJB environment dedicated methods that the EJB provider must develop.

The first set of methods are those corresponding to the create and find methods of the Home interface:

Example

The following examples are for container-managed persistence with EJB 1.1 and EJB 2.0. For bean-managed persistence, refer to the examples delivered with your specific platform.

CMP 1.1

package eb;

import java.rmi.RemoteException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.RemoveException;
import javax.ejb.EJBException;

public class AccountImplBean implements EntityBean {

    // Keep the reference on the EntityContext
    protected EntityContext entityContext;

    // Object state
    public Integer accno;
    public String customer;
    public double balance;

    public Integer ejbCreate(int val_accno, String val_customer, double val_balance) {

        // Init object state
        accno = new Integer(val_accno);
        customer = val_customer;
        balance = val_balance;
        return null;
    }

    public void ejbPostCreate(int val_accno, String val_customer, double val_balance) { 
        // Nothing to be done for this simple example.
    }

    public void ejbActivate() {
        // Nothing to be done for this simple example.
    }

    public void ejbLoad() {
        // Nothing to be done for this simple example, in implicit persistence.
    }

    public void ejbPassivate() {
        // Nothing to be done for this simple example.
    }


    public void ejbRemove() {
        // Nothing to be done for this simple example, in implicit persistence.
    }

    public void ejbStore() {
        // Nothing to be done for this simple example, in implicit persistence.
    }

    public void setEntityContext(EntityContext ctx) {
        // Keep the entity context in object
        entityContext = ctx;
    }

    public void unsetEntityContext() {
        entityContext = null;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double d) {
        balance = balance + d;
    }

    public String  getCustomer() {
        return customer;
    }

    public void setCustomer(String c) {
        customer = c;
    }

    public int getNumber()  {
        return accno.intValue();
    }
}
CMP 2.0
import java.rmi.RemoteException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.RemoveException;
import javax.ejb.CreateException;
import javax.ejb.EJBException;

public abstract class AccountImpl2Bean implements EntityBean {

    // Keep the reference on the EntityContext
    protected EntityContext entityContext;


    /*========================= Abstract set and get accessors for cmp fields ==============*/

    public abstract String getCustomer();
    public abstract void setCustomer(String customer);

    public abstract double getBalance();
    public abstract void setBalance(double balance);

    public abstract int getAccno();
    public abstract void setAccno(int accno);

    /*========================= ejbCreate methods ============================*/


    public Integer ejbCreate(int val_accno, String val_customer, double val_balance) 
        throws CreateException {

        // Init object state
        setAccno(val_accno);
        setCustomer(val_customer);
        setBalance(val_balance);
        return null;
    }
    
    public void ejbPostCreate(int val_accno, String val_customer, double val_balance) { 
        // Nothing to be done for this simple example.
    }


    /*====================== javax.ejb.EntityBean implementation =================*/

    public void ejbActivate() {
        // Nothing to be done for this simple example.
    }

    public void ejbLoad() {
        // Nothing to be done for this simple example, in implicit persistence.
    }

    public void ejbPassivate() {
        // Nothing to be done for this simple example.
    }

    public void ejbRemove() throws RemoveException {
        // Nothing to be done for this simple example, in implicit persistence.
    }

    public void ejbStore() {
        // Nothing to be done for this simple example, in implicit persistence.
    }
  
    public void setEntityContext(EntityContext ctx) { 

        // Keep the entity context in object
        entityContext = ctx;
    }

    public void unsetEntityContext()  {
        entityContext = null;
    }

    /**
     * Business method to get the Account number
     */
    public int getNumber()  {
        return getAccno();
    }

}

Writing Database Access Operations (bean-managed persistence)

For bean-managed persistence, data access operations are developed by the bean provider using the JDBC interface. However, getting database connections must be obtained through the javax.sql.DataSource interface on a datasource object provided by the EJB platform. This is mandatory since the EJB platform is responsible for managing the connection pool and for transaction management. Thus, to get a JDBC connection, in each method performing database operations, the bean provider must: A method that performs database access must always contain the getConnection and close statements, as follows:
public void doSomethingInDB (...) {
    conn = dataSource.getConnection();
    ... // Database access operations
    conn.close();
}
A DataSource object associates a JDBC driver with a database (as an ODBC datasource). It is created and registered in JNDI by the EJB server at launch time (refer also to the section "JDBC DataSources configuration").

A DataSource object is a resource manager connection factory for java.sql.Connection objects, which implements connections to a database management system. The enterprise bean code refers to resource factories using logical names called "Resource manager connection factory references." The resource manager connection factory references are special entries in the enterprise bean environment. The bean provider must use resource manager connection factory references to obtain the datasource object as follow:

The deployer binds the resource manager connection factory references to the actual resource factories that are configured in the server. This binding is done in the JOnAS-specific deployment descriptor using the jonas-resource element.

Example

The declaration of the resource reference in the standard deployment descriptor looks like the following:
<resource-ref>
<res-ref-name>jdbc/AccountExplDs</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
The <res-auth> element indicates which of the two resource manager authentication approaches is used: The JOnAS-specific deployment descriptor must map the environment JNDI name of the resource to the actual JNDI name of the resource object managed by the EJB server. This is done in the <jonas-resource> element.
  <jonas-entity>
    <ejb-name>AccountExpl</ejb-name>
    <jndi-name>AccountExplHome</jndi-name>
    <jonas-resource>
      <res-ref-name>jdbc/AccountExplDs</res-ref-name>
      <jndi-name>jdbc_1</jndi-name>
    </jonas-resource>
  </jonas-entity>
The ejbStore method of the same Account example with bean-managed persistence is shown in the following example. It performs JDBC operations to update the database record representing the state of the entity bean instance. The JDBC connection is obtained from the datasource associated with the bean. This datasource has been instantiated by the EJB server and is available for the bean through its resource reference name, which is defined in the standard deployment descriptor.

In the bean, a reference to a datasource object of the EJB server is initialized:

it = new InitialContext();

ds = (DataSource)it.lookup("java:comp/env/jdbc/AccountExplDs");

Then, this datasource object is used in the implementation of the methods performing JDBC operations, such as ejbStore, as illustrated in the following:

public void ejbStore
    Connection conn = null;
    PreparedStatement stmt = null;
    try { // get a connection
        conn = ds.getConnection();
        // store Object state in DB
        stmt = conn.prepareStatement("update account set customer=?,balance=? where accno=?");
        stmt.setString(1, customer);
        stmt.setDouble(2, balance);
        Integer pk = (Integer)entityContext.getPrimaryKey();
        stmt.setInt(3, pk.accno);
        stmt.executeUpdate();
     } catch (SQLException e) {
        throw new javax.ejb.EJBException("Failed to store bean to database", e);
     } finally {
        try {
            if (stmt != null) stmt.close();    // close statement
            if (conn != null) conn.close();    // release connection
        } catch (Exception ignore) {}
     }
}
Note that the close statement instruction may be important if the server is intensively accessed by many clients performing entity bean access. If the statement is not closed in the finally block, since stmt is in the scope of the method, it will be deleted at the end of the method (and the close will be implicitly done). However, it may be some time before the Java garbage collector deletes the statement object. Therefore, if the number of clients performing entity bean access is important, the DBMS may raise a "too many opened cursors" exception (a JDBC statement corresponds to a DBMS cursor). Since connection pooling is performed by the platform, closing the connection will not result in a physical connection close, therefore opened cursors will not be closed. Thus, it is preferable to explicitly close the statement in the method.

It is a good programming practice to put the JDBC connection and JDBC statement close operations in a finally bloc of the try statement.

Configuring Database Access for Container-managed Persistence

The standard way to indicate to an EJB platform that an entity bean has container-managed persistence is to fill the <persistence-type> tag of the deployment descriptor with the value "container," and to fill the <cmp-field> tag of the deployment descriptor with the list of container-managed fields (the fields that the container will have in charge to make persistent). The CMP version (1.x or 2.x) should also be specified in the <cmp-version> tag. In the textual format of the deployment descriptor, this is represented by the following lines:
    <persistence-type>container</persistence-type>
    <cmp-version>1.x</cmp-version>
    <cmp-field>
      <field-name>fieldOne</field-name>
    </cmp-field>
    <cmp-field>
      <field-name>fieldTwo</field-name>
    </cmp-field>
With container-managed persistence the programmer need not develop the code for accessing the data in the relational database; this code is included in the container itself (generated by the platform tools). However, for the EJB platform to know how to access the database and which data to read and write in the database, two types of information must be provided with the bean: The EJB specification does not specify how this information should be provided to the EJB platform by the bean deployer. Therefore, what is described in the remainder of this section is specific to JOnAS.

For CMP 1.1, the bean deployer is responsible for defining the mapping of the bean fields to the database table columns. The name of the DataSource can be set at deployment time, since it depends on the EJB platform configuration. This database configuration information is defined in the JOnAS-specific deployment descriptor via the jdbc-mapping element. The following example defines the mapping for a CMP 1.1 entity bean:

    <jdbc-mapping>
      <jndi-name>jdbc_1</jndi-name>
      <jdbc-table-name>accountsample</jdbc-table-name>
      <cmp-field-jdbc-mapping>
      <field-name>mAccno</field-name>
      <jdbc-field-name>accno</jdbc-field-name>
      </cmp-field-jdbc-mapping>
      <cmp-field-jdbc-mapping>
      <field-name>mCustomer</field-name>
      <jdbc-field-name>customer</jdbc-field-name>
      </cmp-field-jdbc-mapping>
      <cmp-field-jdbc-mapping>
      <field-name>mBalance</field-name>
      <jdbc-field-name>balance</jdbc-field-name>
    </jdbc-mapping>
jdbc_1 is the JNDI name of the DataSource object identifying the database. accountsample is the name of the table used to store the bean instances in the database. mAccno, mCustomer, and mBalance are the names of the container-managed fields of the bean to be stored in the accno, customer, and balance columns of the accountsample table. This example applies to container-managed persistence. For bean-managed persistence, the database mapping does not exist.

For a CMP 2.0 entity bean, only the jndi-name element of the jdbc-mapping is mandatory, since the mapping may be generated automatically (for an explicit mapping definition, refer to the "JOnAS Database Mapping" section of the Using CMP2.0 persistence chapter):

    <jdbc-mapping>
      <jndi-name>jdbc_1</jndi-name>
    </jdbc-mapping>
    <cleanup>create</cleanup>
For a CMP 2.0 entity bean, the JOnAS-specific deployment descriptor contains an additional element, cleanup, at the same level as the jdbc-mapping element, which can have one of the following values:
removedata
at bean loading time, the content of the tables storing the bean data is deleted
removeall
at bean loading time, the tables storing the bean data are dropped (if they exist) and created
none
do nothing
create
default value (if the element is not specified), at bean loading time, the tables for storing the bean data are created if they do not exist
For CMP 1.1, the jdbc-mapping element can also contain information defining the behaviour of the implementation of a find<method> method (i.e. the ejbFind<method> method, that will be generated by the platform tools). This information is represented by the finder-method-jdbc-mapping element.

For each finder method, this element provides a way to define an SQL WHERE clause that will be used in the generated finder method implementation to query the relational table storing the bean entities. Note that the table column names should be used, not the bean field names. Example:

      <finder-method-jdbc-mapping>
        <jonas-method>
          <method-name>findLargeAccounts</method-name>
        </jonas-method>
        <jdbc-where-clause>where balance &gt; ?</jdbc-where-clause>
      </finder-method-jdbc-mapping>
The previous finder method description will cause the platform tools to generate an implementation of ejbFindLargeAccount(double arg) that returns the primary keys of the entity bean objects corresponding to the tuples returned by the "select ... from Account where balance > ?", where '?' will be replaced by the value of the first argument of the findLargeAccount method. If several '?' characters appear in the provided WHERE clause, this means that the finder method has several arguments and the '?' characters will correspond to these arguments, adhering to the order of the method signature.

In the WHERE clause, the parameters can be followed by a number, which specifies the method parameter number that will be used by the query in this position.
Example: The WHERE clause of the following finder method can be:

      Enumeration findByTextAndDateCondition(String text, java.sql.Date date)

      WHERE (description like ?1 OR summary like ?1) AND (?2 &gt; date)
Note that a <finder-method-jdbc-mapping> element for the findByPrimaryKey method is not necessary, since the meaning of this method is known.

Additionally, note that for CMP 2.0, the information defining the behaviour of the implementation of a find<method> method is located in the standard deployment descriptor, as an EJB-QL query (i.e. this is not JOnAS-specific information). The same finder method example in CMP 2.0:

      <query>
        <query-method>
          <method-name>findLargeAccounts</method-name>
          <method-params>
              <method-param>double</method-param>
          </method-params>
        </query-method>
        <ejb-ql>SELECT OBJECT(o) FROM accountsample o WHERE o.balance &gt; ?1</ejb-ql>
      </query>
The datatypes supported for container-managed fields in CMP 1.1 are the following:
 
Java Type JDBC Type JDBC driver Access methods
boolean BIT getBoolean(), setBoolean()
byte TINYINT getByte(), setByte()
short  SMALLINT getShort(), setShort()
int  INTEGER getInt(), setInt()
long  BIGINT getLong(), setLong()
float  FLOAT getFloat(), setFloat()
double  DOUBLE getDouble(), setDouble
byte[]  VARBINARY or LONGVARBINARY (1) getBytes(), setBytes()
java.lang.String VARCHAR or LONGVARCHAR (1) getString(), setString()
java.lang.Boolean BIT getBoolean(), setObject()
java.lang.Integer INTEGER getInt(), setObject()
java.lang.Short SMALLINT getShort(), setObject()
java.lang.Long BIGINT getLong(), setObject()
java.lang.Float REAL getFloat(), setObject()
java.lang.Double DOUBLE getDouble(), setObject()
java.math.BigDecimal NUMERIC getBigDecimal(), setObject()
java.math.BigInteger NUMERIC getBigDecimal(), setObject()
java.sql.Date DATE getDate(), setDate()
java.sql.Time TIME getTime(), setTime()
java.sql.Timestamp  TIMESTAMP getTimestamp(), setTimestamp()
any serializable class VARBINARY or LONGVARBINARY (1) getBytes(), setBytes()

(1) The mapping for String will normally be VARCHAR, but will turn into LONGVARCHAR if the given value exceeds the driver's limit on VARCHAR values. The case is similar for byte[] and VARBINARY and LONGVARBINARY values.

For CMP 2.0, the supported datatypes depend on the JORM mapper used.

Tuning Container for Entity Bean Optimizations

JOnAS must make a compromise between scalability and performance. Towards this end, we have introduced several tags in the JOnAS-specific deployment descriptor. For most applications, there is no need to change the default values for all these tags. See $JONAS_ROOT/xml/jonas-ejb-jar_3_3_2.dtd for a complete description of the JOnAS-specific deployment descriptor.

Note that if several of these elements are used, they should appear in the following order within the <jonas-entity> element:

  1. is-modified-method-name
  2. passivation-timeout
  3. shared
  4. prefetch
  5. max-cache-size
  6. min-pool-size
  7. lock-policy

lock-policy

The JOnAS ejb container is able to manage 4 different lock-policies :

Important: If you deploy CMP1 beans, you should use the default policy only (container-serialized), unless your beans are "read-only". In this latter case, you can use container-read-uncommitted.

shared

This flag will be defined as true if the bean persistent state can be accessed outside the JOnAS Server. When this flag is false, the JOnAS Server can do some optimization, such as not re-reading the bean state before starting a new transaction. The default value is false if lock-policy is container-serialized, and true in the other cases.

prefetch

This is a CMP2-specific option. The default is false. This can be set to true if it is desirable to have a cache of buffer managed after finder methods, in order to optimize further accesses, inside the same transaction.

Important note :

max-cache-size

This optional integer value represents the maximum of instances in memory. The purpose of this value is to keep JOnAS scalable. The default value is "no limit". To save memory, this value should be set very low if you know that instances will not be reused.

min-pool-size

This optional integer value represents the minimum instances that will be created in the pool when the bean is loaded. This will improve bean instance create time, at least for the first instances. The default value is 0.

is-modified-method-name

To improve performance of CMP 1.1 entity beans, JOnAS implements the isModified extension. Before performing an update, the container calls a method of the bean whose name is identified in the is-modified-method-name element of the JOnAS-specific deployment descriptor. This method is responsible for determining if the state of the bean has been changed. By doing this, the container determines if it must store data in the database or not.

Note that this is useless with CMP2 entity beans, since this will be done automatically by the container.

Example

The bean implementation manages a boolean isDirty and implements a method that returns the value of this boolean: isModified

    
    private transient boolean isDirty;
    public boolean isModified() {
        return isDirty;
    }
    

The JOnAS-specific deployment descriptor directs the bean to implement an isModified method:

 
    <jonas-entity>
      <ejb-name>Item</ejb-name>
      <is-modified-method-name>isModified</is-modified-method-name>
      .....
    </jonas-entity>
    

Methods that modify the value of the bean must set the flag isDirty to true.
Methods that restore the value of the bean from the database must reset the flag isDirty to false. Therefore, the flag must be set to false in the ejbLoad() and ejbStore() methods.

passivation-timeout

Entity bean instances are passivated at the end of the transaction and reactivated at the beginning of the next transaction. In the event that these instances are accessed outside a transaction, their state is kept in memory to improve performance. However, a passivation will occur in three situations:
  1. When the bean is unloaded from the server, at a minimum when the server is stopped.
  2. When a transaction is started on this instance.
  3. After a configurable timeout. If the bean is always accessed with no transaction, it may be prudent to periodically store the bean state on disk.
This passivation timeout can be configured in the JOnAS-specific deployment descriptor, with a non-mandatory tag <passivation-timeout>. Example:
    <jonas-entity>
      <ejb-name>Item</ejb-name>
      <passivation-timeout>5</passivation-timeout>
      .....
    </jonas-entity>
    
This entity bean will be passivated every five second, if not accessed within transactions.

Using CMP2.0 persistence

This section highlights the main differences between CMP as defined in EJB 2.0 specification (called CMP2.0) and CMP as defined in EJB 1.1 specification (called CMP1.1). Major new features in the standard development and deployment of CMP2.0 entity beans are listed (comparing them to CMP1.1), along with JOnAS-specific information. Mapping CMP2.0 entity beans to the database is described in detail. Note that the database mapping can be created entirely by JOnAS, in which case the JOnAS-specific deployment descriptor for an entity bean should contain only the datasource and the element indicating how the database should be initialized.

Standard CMP2.0 Aspects

This section briefly describes the new features available in CMP2.0 as compared to CMP 1.1, and how these features change the development of entity beans.

Entity Bean Implementation Class

The EJB implementation class 1) implements the bean's business methods of the component interface, 2) implements the methods dedicated to the EJB environment (the interface of which is explicitly defined in the EJB specification), and 3) defines the abstract methods representing both the persistent fields (cmp-fields) and the relationship fields (cmr-fields). The class must implement the javax.ejb.EntityBean interface, be defined as public, and be abstract (which is not the case for CMP1.1, where it must not be abstract). The abstract methods are the get and set accessor methods of the bean cmp and cmr fields. Refer to the examples and details in the section "Developing Entity Beans" of the JOnAS documentation.

Standard Deployment Descriptor

The standard way to indicate to an EJB platform that an entity bean has container-managed persistence is to fill the <persistence-type> tag of the deployment descriptor with the value "container," and to fill the <cmp-field> tags of the deployment descriptor with the list of container-managed fields (the fields that the container will have in charge to make persistent) and the <cmr-field> tags identifying the relationships. The CMP version (1.x or 2.x) should also be specified in the <cmp-version> tag. This is represented by the following lines in the deployment descriptor:

    <persistence-type>container</persistence-type>
    <cmp-version>1.x</cmp-version>
    <cmp-field>
      <field-name>fieldOne</field-name>
    </cmp-field>
    <cmp-field>
      <field-name>fieldTwo</field-name>
    </cmp-field>
    

Note that for running CMP1.1-defined entity beans on an EJB2.0 platform, such as JOnAS 3.x, you must introduce this <cmp-version> element in your deployment descriptors, since the default cmp-version value (if not specified) is 2.x.

Note that for CMP 2.0, the information defining the behaviour of the implementation of a find<method> method is located in the standard deployment descriptor as an EJB-QL query (this is not JOnAS-specific information). For CMP 1.1, this information is located in the JOnAS-specific deployment descriptor as an SQL WHERE clause specified in a <finder-method-jdbc-mapping> element.

Finder method example in CMP 2.0: for a findLargeAccounts(double val) method defined on the Account entity bean of the JOnAS eb example.

      <query>
        <query-method>
          <method-name>findLargeAccounts</method-name>
          <method-params>
              <method-param>double</method-param>
          </method-params>
        </query-method>
        <ejb-ql>SELECT OBJECT(o) FROM accountsample o WHERE o.balance &gt; ?1</ejb-ql>
      </query>
    

JOnAS Database mappers

For implementing the EJB 2.0 persistence (CMP2.0), JOnAS relies on the JORM framework. JORM itself relies on JOnAS DataSources (specified in DataSource properties files) for connecting to the actual database. JORM must adapt its object-relational mapping to the underlying database, for which it makes use of adapters called "mappers." Thus, for each type of database (and more precisely for each JDBC driver), the corresponding mapper must be specified in the DataSource. This is the purpose of the datasource.mapper property of the DataSource properties file. Note that all JOnAS-provided DataSource properties files (in JOnAS_ROOT/conf) already contain this property with the correct mapper.

property name description possible values
datasource.mapper JORM database mapper
  • rdb: generic mapper (JDBC standard driver ...)
  • rdb.firebird: Firebird
  • rdb.mckoi: McKoi Db
  • rdb.mysql: MySQL
  • rdb.oracle8: Oracle 8 and lesser versions
  • rdb.oracle: Oracle 9
  • rdb.postgres: PostgreSQL (>= 7.2)
  • rdb.sapdb: Sap DB
  • rdb.sqlserver: MS Sql Server
  • rdb.sybase: Sybase

Contact the JOnAS team to obtain a mapper for other databases.

The container code generated at deployment (GenIC or ejbjar ant task) is dependent on this mapper. It is possible to deploy (generate container code) a bean for several mappers in order to change the database (i.e. the DataSource file) without redeploying the bean. These mappers should be specified as the mappernames argument of the GenIC command or as the mappernames attribute of the JOnAS ANT ejbjar task. The value is a comma-separated list of mapper names for which the container classes will be generated. This list of mapper names corresponds to the list of potential databases upon which you can deploy your entity beans. For example, to deploy entity beans so that they may be used on either Oracle or PostgreSQL, run GenIC as:

         GenIC -mappernames rdb.oracle,rdb.postgres eb.jar
    

The following is the same example in an ANT build.xml file:

  <target name="deploy"
          description="Build and deploy the ejb-jars"
          depends="compile>
    <ejbjar naming="directory"
        ....
        ....
      <jonas destdir="${ejbjars.dir}"
             jonasroot="${jonas.root}"
             orb="${orb}"
             jarsuffix=".jar"
             secpropag="yes"
             keepgenerated="true"
             mappernames="${mapper.names}"
             additionalargs="${genicargs}">
      </jonas>
      ...
      ... 
    </ejbjar>
  </target>
    

having in build.properties:

# mappers for entity CMP2
mapper.names            rdb.oracle,rdb.postgres
    

JOnAS Database Mapping (Specific Deployment Descriptor)

The mapping to the database of entity beans and their relationships may be specified in the JOnAS-specific deployment descriptor, in jonas-entity elements, and in jonas-ejb-relation elements. Since JOnAS is able to generate the database mapping, all the elements of the JOnAS-specific deployment descriptor defined in this section (which are sub-elements of jonas-entity or jonas-ejb-relation) are optional, except those for specifying the datasource and the initialization mode (i.e. the jndi-name of jdbc-mapping and cleanup). The default values of these mapping elements, provided in this section, define the JOnAS-generated database mapping.

Specifying and Initializing the Database

For specifying the database within which a CMP 2.0 entity bean is stored, the jndi-name element of the jdbc-mapping is necessary. This is the JNDI name of the DataSource representing the database storing the entity bean.

    <jdbc-mapping>
      <jndi-name>jdbc_1</jndi-name>
    </jdbc-mapping>
    

For a CMP 2.0 entity bean, the JOnAS-specific deployment descriptor contains an additional element, cleanup, to be specified before the jdbc-mapping element, which can have one of the following values:

removedata
at bean loading time, the content of the tables storing the bean data is deleted
removeall
at bean loading time, the tables storing the bean data are dropped (if they exist) and created
none
do nothing
create
default value (if the element is not specified), at bean loading time, the tables for storing the bean data are created if they do not exist.

It may be useful for testing purposes to delete the database data each time a bean is loaded. For this purpose, the part of the JOnAS-specific deployment descriptor related to the entity bean may look like the following:

    <cleanup>removedata</cleanup>
    <jdbc-mapping>
      <jndi-name>jdbc_1</jndi-name>
    </jdbc-mapping>
    

CMP fields Mapping

Mapping CMP fields in CMP2.0 is similar to that of CMP 1.1, but in CMP2.0 it is also possible to specify the SQL type of a column. Usually this SQL type is used if JOnAS creates the table (create value of the cleanup element), and if the JORM default chosen SQL type is not appropriate.

Standard Deployment Descriptor
    .....
    <entity>
      <ejb-name>A</ejb-name>
      .....
      <cmp-field>
        <field-name>idA</field-name>
      </cmp-field>
      <cmp-field>
        <field-name>f</field-name>
      </cmp-field>
    .....
    </entity>
    .....
    
Database Mapping
t_A
c_idA c_f
... ...
JOnAS Deployment Descriptor
    .....
    <jonas-entity>
      <ejb-name>A</ejb-name>
      .....
      <jdbc-mapping>
        <jndi-name>jdbc_1</jndi-name>
        <jdbc-table-name>t_A</jdbc-table-name>
        <cmp-field-jdbc-mapping>
          <field-name>idA</field-name>
          <jdbc-field-name>c_idA</jdbc-field-name>
        </cmp-field-jdbc-mapping>
        <cmp-field-jdbc-mapping>
          <field-name>f</field-name>
          <jdbc-field-name>c_f</jdbc-field-name>
          <sql-type>varchar(40)</sql-type>
        </cmp-field-jdbc-mapping>
      </jdbc-mapping>
      .....
    </jonas-entity>
    .....
    

Defaults values:

jndi-name Mandatory
jdbc-table-name Optional.
Default value is the upper-case CMP2 abstract-schema-name, or the CMP1 ejb-name, suffixed by _.
cmp-field-jdbc-mapping Optional.
jdbc-field-name Optional.
Default value is the field-name suffixed by _.
idA_ and f_ in the example.
sql-type Optional.
Default value defined by JORM.
 

CMR fields Mapping to primary-key-fields (simple pk)

1-1 unidirectional relationships
Standard Deployment Descriptor
    .....
    <entity>
      <ejb-name>A</ejb-name>
      .....
      <cmp-field>
        <field-name>idA</field-name>
      </cmp-field>
      <primkey-field>idA</primkey-field>
      .....
    </entity>
    .....
    <entity>
      <ejb-name>B</ejb-name>
      .....
      <cmp-field>
        <field-name>idB</field-name>
      </cmp-field>
      <primkey-field>idB</primkey-field>
      .....
    </entity>
    .....
    <relationships>
      <ejb-relation>
        <ejb-relation-name>a-b</ejb-relation-name>
        <ejb-relationship-role>
          <!-- A => B -->
                <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
          <multiplicity>One</multiplicity>
          <relationship-role-source>
            <ejb-name>A</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>b</cmr-field-name>
          </cmr-field>
        </ejb-relationship-role>
        <ejb-relationship-role>
          <!-- B => A -->
          <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
          <multiplicity>One</multiplicity>
          <relationship-role-source>
            <ejb-name>B</ejb-name>
          </relationship-role-source>
        </ejb-relationship-role>
      </ejb-relation>
    </relationships>
    .....
    
Database Mapping
t_A
c_idA cfk_idB
... ...
t_B
c_idB
...

There is a foreign key in the table of the bean that owns the CMR field.

JOnAS Deployment Descriptor
    .....
    <jonas-entity>
      <ejb-name>A</ejb-name>
      .....
      <jdbc-mapping>
        <jndi-name>jdbc_1</jndi-name>
        <jdbc-table-name>t_A/jdbc-table-name>
        <cmp-field-jdbc-mapping>
          <field-name>idA</field-name>
          <jdbc-field-name>c_idA</jdbc-field-name>
        </cmp-field-jdbc-mapping>
      </jdbc-mapping>
      .....
    </jonas-entity>
    .....
    <jonas-entity>
      <ejb-name>B</ejb-name>
      .....
      <jdbc-mapping>
        <jndi-name>jdbc_1</jndi-name>
        <jdbc-table-name>t_B/jdbc-table-name>
        <cmp-field-jdbc-mapping>
          <field-name>idB</field-name>
          <jdbc-field-name>c_idB</jdbc-field-name>
        </cmp-field-jdbc-mapping>
      </jdbc-mapping>
      .....
    </jonas-entity>
    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_idb</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

foreign-key-jdbc-name is the column name of the foreign key in the table of the source bean of the relationship-role.
In this example, where the destination bean has a primary-key-field, it is possible to deduce that this foreign-key-jdbc-name column is to be associated with the column of this primary-key-field in the table of the destination bean.

Default values:

jonas-ejb-relation Optional
foreign-key-jdbc-name Optional.
Default value is the abstract-schema-name of the destination bean, suffixed by _, and by its primary-key-field.
B_idb in the example.
 
1-1 bidirectional relationships

Compared to 1-1 unidirectional relationships, there is a CMR field in both of the beans, thus making two types of mapping possible.

Standard Deployment Descriptor
    .....
    <relationships>
      <ejb-relation>
        <ejb-relation-name>a-b</ejb-relation-name>
        <ejb-relationship-role>
          <!-- A => B -->
                <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
          <multiplicity>One</multiplicity>
          <relationship-role-source>
            <ejb-name>A</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>b</cmr-field-name>
          </cmr-field>
        </ejb-relationship-role>
        <ejb-relationship-role>
          <!-- B => A -->
          <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
          <multiplicity>One</multiplicity>
          <relationship-role-source>
            <ejb-name>B</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>a</cmr-field-name>
          </cmr-field>
        </ejb-relationship-role>
      </ejb-relation>
    </relationships>
    .....
    
Database Mapping

Two mappings are possible. One of the tables may hold a foreign key.

Case 1:

t_A
c_idA cfk_idB
... ...
t_B
c_idB
...

Case 2:

t_A
c_idA
...
t_B
c_idB cfk_idA
... ...
JOnAS Deployment Descriptor

Case 1:

    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_idb</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

Case 2:

    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_ida</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

For the default mapping, the foreign key is in the table of the source bean of the first ejb-relationship-role of the ejb-relation. In the example, the default mapping corresponds to case 1, since the ejb-relationship-role a2b is the first defined in the ejb-relation a-b. Then, the default values are similar to those of the 1-1 unidirectional relationship.

 
1-N unidirectional relationships
Standard Deployment Descriptor
    .....
    <relationships>
      <ejb-relation>
        <ejb-relation-name>a-b</ejb-relation-name>
        <ejb-relationship-role>
          <!-- A => B -->
                <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
          <multiplicity>One</multiplicity>
          <relationship-role-source>
            <ejb-name>A</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>b</cmr-field-name>
            <cmr-field-type>java.util.Collection</cmr-field-type>
          </cmr-field>
        </ejb-relationship-role>
        <ejb-relationship-role>
          <!-- B => A -->
          <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
          <multiplicity>Many</multiplicity>
          <relationship-role-source>
            <ejb-name>B</ejb-name>
          </relationship-role-source>
        </ejb-relationship-role>
      </ejb-relation>
    </relationships>
    .....
    
Database Mapping
t_A
c_idA
...
t_B
c_idB cfk_idA
... ...

In this case, the foreign key must be in the table of the bean which is on the "many" side of the relationship (i.e. in the table of the source bean of the relationship role with multiplicity many), t_B.

JOnAS Deployment Descriptor
    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_ida</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

Default values:

jonas-ejb-relation Optional
foreign-key-jdbc-name Optional.
Default value is the abstract-schema-name of the destination bean of the "one" side of the relationship (i.e. the source bean of the relationship role with multiplicity one), suffixed by _, and by its primary-key-field.
A_ida in the example.
 
1-N bidirectional relationships

Similar to 1-N unidirectional relationships, but with a CMR field in each bean.

Standard Deployment Descriptor
    .....
    <relationships>
      <ejb-relation>
        <ejb-relation-name>a-b</ejb-relation-name>
        <ejb-relationship-role>
          <!-- A => B -->
                <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
          <multiplicity>One</multiplicity>
          <relationship-role-source>
            <ejb-name>A</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>b</cmr-field-name>
            <cmr-field-type>java.util.Collection</cmr-field-type>
          </cmr-field>
        </ejb-relationship-role>
        <ejb-relationship-role>
          <!-- B => A -->
          <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
          <multiplicity>Many</multiplicity>
          <relationship-role-source>
            <ejb-name>B</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>a</cmr-field-name>
          </cmr-field>
        </ejb-relationship-role>
      </ejb-relation>
    </relationships>
    .....
    
Database mapping
t_A
c_idA
...
t_B
c_idB cfk_idA
... ...

In this case, the foreign key must be in the table of the bean which is on the "many" side of the relationship (i.e. in the table of the source bean of the relationship role with multiplicity many), t_B.

JOnAS Deployment Descriptor
    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_ida</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

Default values:

jonas-ejb-relation Optional
foreign-key-jdbc-name Optional.
Default value is the abstract-schema-name of the destination bean of the "one" side of the relationship (i.e. the source bean of the relationship role with multiplicity one), suffixed by _, and by its primary-key-field.
A_ida in the example.
 
N-1 unidirectional relationships

Similar to 1-N unidirectional relationships, but the CMR field is defined on the "many" side of the relationship, i.e. on the (source bean of the) relationship role with multiplicity "many."

Standard Deployment Descriptor
    .....
    <relationships>
      <ejb-relation>
        <ejb-relation-name>a-b</ejb-relation-name>
        <ejb-relationship-role>
          <!-- A => B -->
                <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
          <multiplicity>Many</multiplicity>
          <relationship-role-source>
            <ejb-name>A</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>b</cmr-field-name>
          </cmr-field>
        </ejb-relationship-role>
        <ejb-relationship-role>
          <!-- B => A -->
          <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
          <multiplicity>One</multiplicity>
          <relationship-role-source>
            <ejb-name>B</ejb-name>
          </relationship-role-source>
        </ejb-relationship-role>
      </ejb-relation>
    </relationships>
    .....
    
Database mapping
t_A
c_idA cfk_idB
... ...
t_B
c_idB
...

In this case, the foreign key must be in the table of the bean which is on the "many" side of the relationship (i.e. in table of the source bean of the relationship role with multiplicity many), t_A.

JOnAS Deployment Descriptor
    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_idb</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

Default values:

jonas-ejb-relation Optional
foreign-key-jdbc-name Optional.
Default value is the abstract-schema-name of the destination bean of the "one" side of the relationship (i.e. the source bean of the relationship role with multiplicity one), suffixed by _, and by its primary-key-field.
B_idb in the example.
 
N-M unidirectional relationships
Standard Deployment Descriptor
    .....
    <relationships>
      <ejb-relation>
        <ejb-relation-name>a-b</ejb-relation-name>
        <ejb-relationship-role>
          <!-- A => B -->
                <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
          <multiplicity>Many</multiplicity>
          <relationship-role-source>
            <ejb-name>A</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>b</cmr-field-name>
            <cmr-field-type>java.util.Collection</cmr-field-type>
          </cmr-field>
        </ejb-relationship-role>
        <ejb-relationship-role>
          <!-- B => A -->
          <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
          <multiplicity>Many</multiplicity>
          <relationship-role-source>
            <ejb-name>B</ejb-name>
          </relationship-role-source>
        </ejb-relationship-role>
      </ejb-relation>
    </relationships>
    .....
    
Database mapping
t_A
c_idA
...
t_B
c_idB
...
tJoin_AB
cfk_idA cfk_idB
... ...

In this case, there is a join table composed of the foreign keys of each entity bean table.

JOnAS Deployment Descriptor
    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jdbc-table-name>tJoin_AB</jdbc-table-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_idb</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_ida</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

Default values

jonas-ejb-relation Optional
jdbc-table-name Optional.
Default value is built from the abstract-schema-names of the beans, separated by _.
A_B in the example.
foreign-key-jdbc-name Optional.
Default value is the abstract-schema-name of the destination bean, suffixed by _, and by its primary-key-field.
B_idb and A_ida in the example.
 
N-M bidirectional relationships

Similar to N-M unidirectional relationships, but a CMR field is defined for each bean.

Standard deployment Descriptor
    .....
    <relationships>
      <ejb-relation>
        <ejb-relation-name>a-b</ejb-relation-name>
        <ejb-relationship-role>
          <!-- A => B -->
                <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
          <multiplicity>Many</multiplicity>
          <relationship-role-source>
            <ejb-name>A</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>b</cmr-field-name>
            <cmr-field-type>java.util.Collection</cmr-field-type>
          </cmr-field>
        </ejb-relationship-role>
        <ejb-relationship-role>
          <!-- B => A -->
          <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
          <multiplicity>Many</multiplicity>
          <relationship-role-source>
            <ejb-name>B</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>a</cmr-field-name>
            <cmr-field-type>java.util.Collection</cmr-field-type>
          </cmr-field>
        </ejb-relationship-role>
      </ejb-relation>
    </relationships>
    .....
    
Database mapping
t_A
c_idA
...
t_B
c_idB
...
tJoin_AB
cfk_idA cfk_idB
... ...

In this case, there is a join table composed of the foreign keys of each entity bean table.

JOnAS Deployment Descriptor
    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jdbc-table-name>tJoin_AB</jdbc-table-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_idb</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_ida</foreign-key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

Default values:

jonas-ejb-relation Optional
jdbc-table-name Optional.
Default value is built from the abstract-schema-names of the beans, separated by _.
A_B in the example.
foreign-key-jdbc-name Optional.
Default value is the abstract-schema-name of the destination bean, suffixed by _, and by its primary-key-field.
B_idb and A_ida in the example.
 

CMR fields Mapping to composite primary-keys

In the case of composite primary keys, the database mapping should provide the capability to specify which column of a foreign key corresponds to which column of the primary key. This is the only difference between relationships based on simple primary keys. For this reason, not all types of relationship are illustrated below.

1-1 bidirectional relationships
Standard Deployment Descriptor
    .....
    <entity>
      <ejb-name>A</ejb-name>
      .....
      <prim-key-class>p.PkA</prim-key-class>
      .....
      <cmp-field>
        <field-name>id1A</field-name>
      </cmp-field>
      <cmp-field>
        <field-name>id2A</field-name>
      </cmp-field>
      .....
    </entity>
    .....
    <entity>
      <ejb-name>B</ejb-name>
      .....
      <prim-key-class>p.PkB</prim-key-class>
      .....
      <cmp-field>
        <field-name>id1B</field-name>
      </cmp-field>
      <cmp-field>
        <field-name>id2B</field-name>
      </cmp-field>
      .....
    </entity>
    .....
    <relationships>
      <ejb-relation>
        <ejb-relation-name>a-b</ejb-relation-name>
        <ejb-relationship-role>
          <!-- A => B -->
                <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
          <multiplicity>One</multiplicity>
          <relationship-role-source>
            <ejb-name>A</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>b</cmr-field-name>
          </cmr-field>
        </ejb-relationship-role>
        <ejb-relationship-role>
          <!-- B => A -->
          <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
          <multiplicity>One</multiplicity>
          <relationship-role-source>
            <ejb-name>B</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>a</cmr-field-name>
          </cmr-field>
        </ejb-relationship-role>
      </ejb-relation>
    </relationships>
    .....
    
Database mapping

Two mappings are possible, one or another of the tables may hold the foreign key.

Case 1:

t_A
c_id1A c_id2A cfk_id1B cfk_id2B
... ... ... ...
t_B
c_id1B c_id2B
... ...

Case 2:

t_A
c_id1A c_id2A
... ...
t_B
c_id1B c_id2B cfk_id1A cfk_id2A
... ... ... ...
JOnAS Deployment Descriptor

Case 1:

    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_id1b</foreign-key-jdbc-name>
          <key-jdbc-name>c_id1b</key-jdbc-name>
        </foreign-key-jdbc-mapping>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_id2b</foreign-key-jdbc-name>
          <key-jdbc-name>c_id2b</key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

Case 2:

    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_id1a</foreign-key-jdbc-name>
          <key-jdbc-name>c_id1a</key-jdbc-name>
        </foreign-key-jdbc-mapping>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_id2a</foreign-key-jdbc-name>
          <key-jdbc-name>c_id2a</key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....
    

For the default mapping (values), the foreign key is in the table of the source bean of the first ejb-relationship-role of the ejb-relation. In the example, the default mapping corresponds to case 1, since the ejb-relationship-role a2b is the first defined in the ejb-relation a-b.

 
N-M unidirectional relationships
Standard Deployment Descriptor
    .....
    <entity>
      <ejb-name>A</ejb-name>
      .....
      <cmp-field>
        <field-name>id1A</field-name>
      </cmp-field>
      <cmp-field>
        <field-name>id2A</field-name>
      </cmp-field>
      .....
    </entity>
    .....
    <entity>
      <ejb-name>B</ejb-name>
      .....
      <cmp-field>
        <field-name>id1B</field-name>
      </cmp-field>
      <cmp-field>
        <field-name>id2B</field-name>
      </cmp-field>
      .....
    </entity>
    .....
    <relationships>
      <ejb-relation>
        <ejb-relation-name>a-b</ejb-relation-name>
        <ejb-relationship-role>
          <!-- A => B -->
                <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
          <multiplicity>Many</multiplicity>
          <relationship-role-source>
            <ejb-name>A</ejb-name>
          </relationship-role-source>
          <cmr-field>
            <cmr-field-name>b</cmr-field-name>
            <cmr-field-type>java.util.Collection</cmr-field-type>
          </cmr-field>
        </ejb-relationship-role>
        <ejb-relationship-role>
          <!-- B => A -->
          <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
          <multiplicity>Many</multiplicity>
          <relationship-role-source>
            <ejb-name>B</ejb-name>
          </relationship-role-source>
        </ejb-relationship-role>
      </ejb-relation>
    </relationships>
    .....
    
Database mapping
t_A
c_id1A c_id2A
... ...
t_B
c_id1B c_id2B
... ...
tJoin_AB
cfk_id1A cfk_id2A cfk_id1B cfk_id2B
... ... ... ...

In this case, there is a join table composed of the foreign keys of each entity bean table.

JOnAS Deployment Descriptor
    .....
    <jonas-ejb-relation>
      <ejb-relation-name>a-b</ejb-relation-name>
      <jdbc-table-name>tJoin_AB</jdbc-table-name>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>a2b</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_id1b</foreign-key-jdbc-name>
          <key-jdbc-name>c_id1b</key-jdbc-name>
        </foreign-key-jdbc-mapping>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_id2b</foreign-key-jdbc-name>
          <key-jdbc-name>c_id2b</key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
      <jonas-ejb-relationship-role>
        <ejb-relationship-role-name>b2a</ejb-relationship-role-name>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_id1a</foreign-key-jdbc-name>
          <key-jdbc-name>c_id1a</key-jdbc-name>
        </foreign-key-jdbc-mapping>
        <foreign-key-jdbc-mapping>
          <foreign-key-jdbc-name>cfk_id2a</foreign-key-jdbc-name>
          <key-jdbc-name>c_id2a</key-jdbc-name>
        </foreign-key-jdbc-mapping>
      </jonas-ejb-relationship-role>
    </jonas-ejb-relation>
    .....