31.3. Entity Beans
We will start our look at entity beans in JBoss by examining one of the CMP entity beans in the crime portal. We will look at the gangster bean, which is implemented as local CMP entity bean. Although JBoss can provide remote entity beans with pass-by-reference semantics for calls in the same VM to get the performance benefit as from local entity beans, the use of local entity beans is strongly encouraged.
We will start with the required home interface. Since we are only concerned with the CMP fields at this point, we will show only the methods dealing with the CMP fields.
// Gangster Local Home Interface public interface GangsterHome extends EJBLocalHome { Gangster create(Integer id, String name, String nickName) throws CreateException; Gangster findByPrimaryKey(Integer id) throws FinderException; }
The local interface is what clients will use to talk. Again, it contains only the CMP field accessors.
// Gangster Local Interface public interface Gangster extends EJBLocalObject { Integer getGangsterId(); String getName(); String getNickName(); void setNickName(String nickName); int getBadness(); void setBadness(int badness); }
Finally, we have the actual gangster bean. Despite it's size, very little code is actually required. The bulk of the class is the create method.
// Gangster Implementation Class public abstract class GangsterBean implements EntityBean { private EntityContext ctx; private Category log = Category.getInstance(getClass()); public Integer ejbCreate(Integer id, String name, String nickName) throws CreateException { log.info("Creating Gangster " + id + " '" + nickName + "' "+ name); setGangsterId(id); setName(name); setNickName(nickName); return null; } public void ejbPostCreate(Integer id, String name, String nickName) { } // CMP field accessors --------------------------------------------- public abstract Integer getGangsterId(); public abstract void setGangsterId(Integer gangsterId); public abstract String getName(); public abstract void setName(String name); public abstract String getNickName(); public abstract void setNickName(String nickName); public abstract int getBadness(); public abstract void setBadness(int badness); public abstract ContactInfo getContactInfo(); public abstract void setContactInfo(ContactInfo contactInfo); //... // EJB callbacks --------------------------------------------------- public void setEntityContext(EntityContext context) { ctx = context; } public void unsetEntityContext() { ctx = null; } public void ejbActivate() { } public void ejbPassivate() { } public void ejbRemove() { log.info("Removing " + getName()); } public void ejbStore() { } public void ejbLoad() { } }
The only thing missing now is the
ejb-jar.xml
deployment descriptor. Although the actual bean class is named GangsterBean
, we've called the entity GangsterEJB
.
<?xml version="1.0" encoding="UTF-8"?> <ejb-jar xmlns="http://java.sun.com/xml/ns/"Whats_new_in_JBoss_4-J2EE_Certification_and_Standards_Compliance" version="2.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_\2_1.xsd"> <display-name>Crime Portal</display-name> <enterprise-beans> <entity> <display-name>Gangster Entity Bean</display-name> <ejb-name>GangsterEJB</ejb-name> <local-home>org.jboss.cmp2.crimeportal.GangsterHome</local-home> <local>org.jboss.cmp2.crimeportal.Gangster</local> <ejb-class>org.jboss.cmp2.crimeportal.GangsterBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.Integer</prim-key-class> <reentrant>False</reentrant> <cmp-version>2.x</cmp-version> <abstract-schema-name>gangster</abstract-schema-name> <cmp-field> <field-name>gangsterId</field-name> </cmp-field> <cmp-field> <field-name>name</field-name> </cmp-field> <cmp-field> <field-name>nickName</field-name> </cmp-field> <cmp-field> <field-name>badness</field-name> </cmp-field> <cmp-field> <field-name>contactInfo</field-name> </cmp-field> <primkey-field>gangsterId</primkey-field> <!-- ... --> </entity> </enterprise-beans> </ejb-jar>
Note that we've specified a CMP version of
2.x
to indicate that this is EJB 2.x CMP entity bean. The abstract schema name was set to gangster
. That will be important when we look at EJB-QL queries in Section 31.6, “Queries”.
31.3.1. Entity Mapping
The JBoss configuration for the entity is declared with an
entity
element in the jbosscmp-jdbc.xml
file. This file is located in the META-INF
directory of the EJB JAR and contains all of the optional configuration information for configuring the CMP mapping. The entity
elements for each entity bean are grouped together in the enterprise-beans
element under the top level jbosscmp-jdbc
element. A stubbed out entity configuration is shown below.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE jbosscmp-jdbc PUBLIC "-//JBoss//DTD JBOSSCMP-JDBC 3.2//EN" "http://www.jboss.org/j2ee/dtd/jbosscmp-jdbc_3_2.dtd"> <jbosscmp-jdbc> <defaults> <!-- application-wide CMP defaults --> </defaults> <enterprise-beans> <entity> <ejb-name>GangsterEJB</ejb-name> <!-- overrides to defaults section --> <table-name>gangster</table-name> <!-- CMP Fields (see CMP-Fields) --> <!-- Load Groups (see Load Groups)--> <!-- Queries (see Queries) --> </entity> </enterprise-beans> </jbosscmp-jdbc>
The
ejb-name
element is required to match the entity specification here with the one in the ejb-jar.xml
file. The remainder of the elements specify either overrides the global or application-wide CMP defaults and CMP mapping details specific to the bean. The application defaults come from the defaults
section of the jbosscmp-jdbc.xml
file and the global defaults come from the defaults
section of the standardjbosscmp-jdbc.xml
file in the conf
directory for the current server configuration file set. The defaults
section is discussed in Section 31.12, “Defaults”. Figure 31.3, “The entity element content model” shows the full entity
content model.
Figure 31.3. The entity element content model
A detailed description of each entity element follows:
- ejb-name: This required element is the name of the EJB to which this configuration applies. This element must match an
ejb-name
of an entity in theejb-jar.xml
file. - datasource: This optional element is the
jndi-name
used to look up the datasource. All database connections used by an entity or relation-table are obtained from the datasource. Having different datasources for entities is not recommended, as it vastly constrains the domain over which finders and ejbSelects can query. The default isjava:/DefaultDS
unless overridden in the defaults section. - datasource-mapping: This optional element specifies the name of the
type-mapping
, which determines how Java types are mapped to SQL types, and how EJB-QL functions are mapped to database specific functions. Type mappings are discussed in Section 31.13.3, “Mapping”. The default isHypersonic SQL
unless overridden in the defaults section. - create-table: This optional element when true, specifies that JBoss should attempt to create a table for the entity. When the application is deployed, JBoss checks if a table already exists before creating the table. If a table is found, it is logged, and the table is not created. This option is very useful during the early stages of development when the table structure changes often. The default is false unless overridden in the defaults section.
- alter-table: If
create-table
is used to automatically create the schema,alter-table
can be used to keep the schema current with changes to the entity bean. Alter table will perform the following specific tasks:- new fields will be created
- fields which are no longer used will be removed
- string fields which are shorter than the declared length will have their length increased to the declared length. (not supported by all databases)
- remove-table: This optional element when true, JBoss will attempt to drop the table for each entity and each relation table mapped relationship. When the application is undeployed, JBoss will attempt to drop the table. This option is very useful during the early stages of development when the table structure changes often. The default is false unless overridden in the defaults section.
- post-table-create: This optional element specifies an arbitrary SQL statement that should be executed immediately after the database table is created. This command is only executed if
create-table
is true and the table did not previously exist. - read-only: This optional element when true specifies that the bean provider will not be allowed to change the value of any fields. A field that is read-only will not be stored in, or inserted into, the database. If a primary key field is read-only, the create method will throw a
CreateException
. If a set accessor is called on a read-only field, it throws anEJBException
. Read-only fields are useful for fields that are filled in by database triggers, such as last update. Theread-only
option can be overridden on a percmp-field
basis, and is discussed in Section 31.4.3, “Read-only Fields”. The default is false unless overridden in thedefaults
section. - read-time-out: This optional element is the amount of time in milliseconds that a read on a read-only field is valid. A value of 0 means that the value is always reloaded at the start of a transaction, and a value of -1 means that the value never times out. This option can also be overridden on a per
cmp-field
basis. Ifread-only
is false, this value is ignored. The default is -1 unless overridden in thedefaults
section. - row-locking: This optional element if true specifies that JBoss will lock all rows loaded in a transaction. Most databases implement this by using the
SELECT FOR UPDATE
syntax when loading the entity, but the actual syntax is determined by therow-locking-template
in the datasource-mapping used by this entity. The default is false unless overridden in thedefaults
section. - pk-constraint: This optional element if true specifies that JBoss will add a primary key constraint when creating tables. The default is true unless overridden in the defaults section.
- read-ahead: This optional element controls caching of query results and
cmr-fields
for the entity. This option is discussed in Section 31.7.3, “Read-ahead”. - fetch-size: This optional element specifies the number of entities to read in one round-trip to the underlying datastore. The default is 0 unless overridden in the defaults section.
- list-cache-max: This optional element specifies the number of read-lists that can be tracked by this entity. This option is discussed in
on-load
. The default is 1000 unless overridden in the defaults section. - clean-read-ahead-on-load: When an entity is loaded from the read ahead cache, JBoss can remove the data used from the read ahead cache. The default is
false
. - table-name: This optional element is the name of the table that will hold data for this entity. Each entity instance will be stored in one row of this table. The default is the
ejb-name
. - cmp-field: The optional element allows one to define how the
ejb-jar.xml
cmp-field
is mapped onto the persistence store. This is discussed in Section 31.4, “CMP Fields”. - load-groups: This optional element specifies one or more groupings of CMP fields to declare load groupings of fields. This is discussed in Section 31.7.2, “Load Groups”.
- eager-load-groups: This optional element defines one or more load grouping as eager load groups. This is discussed in Section 31.8.2, “Eager-loading Process”.
- lazy-load-groups: This optional element defines one or more load grouping as lazy load groups. This is discussed in Section 31.8.3, “Lazy loading Process”.
- query: This optional element specifies the definition of finders and selectors. This is discussed in Section 31.6, “Queries”.
- unknown-pk: This optional element allows one to define how an unknown primary key type of
java.lang.Object
maps to the persistent store. - entity-command: This optional element allows one to define the entity creation command instance. Typically this is used to define a custom command instance to allow for primary key generation. This is described in detail in Section 31.11, “Entity Commands and Primary Key Generation”.
- optimistic-locking: This optional element defines the strategy to use for optimistic locking. This is described in detail in Section 31.10, “Optimistic Locking”.
- audit: This optional element defines the CMP fields that will be audited. This is described in detail in Section 31.4.4, “Auditing Entity Access”.