Field-based Persistent Objects
Resin 3.0

Features
Installation
Configuration
Web Applications
IOC/AOP
Resources
JSP
Servlets and Filters
Portlets
Databases
Admin (JMX)
CMP
EJB
EJB 3.0
Security
XML and XSLT
XTP
JMS
Performance
Protocols
Third-party
Troubleshooting/FAQ

Bean Annotation
Table
Tutorials

CMP Field
Transactions
CMP Basic
CMP Create
CMP Transactions
CMP Query
CMP Many-to-One
CMP One-to-Many
CMP Many-to-Many
CMP Inherit
Stateless Session
Tutorials
Tutorials
Transactions

Find this tutorial in: /usr/local/resin/resin-3.0.12/webapps/resin-doc/ejb3/tutorial/cmp-basic-field
Try the Tutorial

EJB 3.0 supports a field-based relational model: each Java field represents a database column. The tutorial shows the configuration, classes, and client code for a single-table entity.

  1. Overview
    1. Differences with EJB 2.1
  2. Files in this tutorial
  3. Database Model
  4. Persistent Object Implementation
    1. @Entity - marking the class as persistent
    2. @Table - naming the table
    3. @Id - marking the primary key
    4. @Basic - marking a persistent field
    5. @Column - naming the column
    6. Under the covers: bytecode enhancement
  5. Client Servlet
    1. EntityManager
    2. Query
  6. Resin Configuration

Overview

EJB 3.0 provides a Java model for a relational database, focusing on solving that single, specific problem. Earlier EJB versions overgeneralized, trying to support non-relational data, and lost focus and clarity. Other persistent object specifications, like JDO, tried to provide transparent persistence for Java objects and tried to support both object and relational databases. By restricting to relational database mapping, EJB 3.0 can provide powerful Java models and still simplify the specification and its use.

A typical project using EJB 3.0 starts planning with the relational database schema and matching the Java model to that schema. This data-driven approach contrasts with a transparent persistent object approach which starts with Java classes and then tries to create storage to match the Java model, an approach more typical of object-oriented databases. While the transparent persistence model may be appropriate for some applications, EJB 3.0 wisely leaves transparent persistence to other products and specifications, and concentrates on the relational database model.

In a way, EJB 3.0 simply provides an extension to SQL queries, returning fully-populated Java objects instead of just returning primitive values like Strings. That somewhat understates EJB's capabilities since the Java objects are live, updating the database in a object-oriented fashion, and also provides caching. Still, viewing EJB 3.0 as a SQL extension supporting relations and objects is a good starting model.

The tutorial uses "entity" to mean a persistent object. In EJB 3.0, an entity is a Java class instance.

Differences with EJB 2.1

The EJB 3.0 draft is primarily a process of removing features superfluous to supporting persistent objects.

  • No home interfaces
  • No local interfaces
  • No instance pooling
  • No special create or remove methods
  • No special find or select methods
  • Deployment descriptor is optional

EJB 3.0 relies on JDK 1.5 annotations to configure entities in a maintainable, self-documenting way.

  • Only one Java class needed per table (no interface needed)
  • Annotation per field
  • Annotation directly in Java class
  • Direct java instance (no proxy or stub needed)

Files in this tutorial

WEB-INF/web.xml web.xml configuration
WEB-INF/classes/example/Course.java The course bean
WEB-INF/classes/example/CourseServlet.java The course servlet

Database Model

The tutorial's design begins with its database model. The table is a collection of school courses, each with an assigned teacher. The table has an integer primary key "id" and two string data fields, "course" and "teacher".

course.sql
CREATE TABLE ejb3_basic_courses (
  id INTEGER PRIMARY KEY auto_increment,

  course VARCHAR(250),
  teacher VARCHAR(250)
);

INSERT INTO ejb3_basic_courses VALUES('Potions', 'Severus Snape');
INSERT INTO ejb3_basic_courses VALUES('Transfiguration', 'Minerva McGonagall');

To judge the complexity of EJB 3.0, it's useful to compare the EJB Java model to the simplest possible Java model. The simple model has a single class, Course, for the table and three fields for the table's columns.

Minimal Java model
package example;

public class Course {
  private int _id;
  private String _course;
  private String _teacher;
}

The minimal class is missing any description of its intended use as a persistent object, information needed for maintainable code. In theory, a persistent object tool could use the minimal class automatically, but without more information, the source doesn't properly describe the class behavior. Fortunately, the JDK 1.5 metadata annotations can describe the persistence information in a maintainable, self-documenting way.

Of course, those annotations might have default values and should be overridable by an optional XML configuration file, but it's necessary to annotate the intended function of the entity in the Java source itself to properly document and validate the Java code.

Persistent Object Implementation

The minimal Java class needs the following annotations to produce a maintainable persistent object:

  • A annotation to mark the class as persistent.
  • An annotation naming the relational table for the class.
  • An annotation to mark the primary key and any auto-generation capability.
  • Annotations to mark each persistent field.
  • Annotations naming the columns for the table.

The following code shows the EJB 3.0 annotations for the course entity. As a quick comparison with the minimal Java class shows, EJB 3.0 is close to the simplest possible implementation of the Java model which provides the necessary annotations in the list.

Course.java
package example;

@javax.ejb.Entity (access=javax.ejb.AccessType.FIELD)
@javax.ejb.Table (name="ejb3_basic_course")
public class Course {
  @javax.ejb.Id (generator=javax.ejb.GeneratorType.AUTO)
  @javax.ejb.Column (name="id")
  private int _id;

  @javax.ejb.Basic 
  @javax.ejb.Column (name="course")
  private String _course;

  @javax.ejb.Basic 
  @javax.ejb.Column (name="teacher")
  private String _teacher;

  public String course()
  {
    return _course;
  }

  public String teacher()
  {
    return _teacher;
  }
}

The example uses the course() and teacher() methods to emphasize that the field accesses to _course and _teacher are live, i.e. they read and write the database values directly. (Under the covers, Resin uses bytecode enhancement to make this work.)

@Entity - marking the class as persistent

Course uses the @Entity to mark the Java class as a field-based persistent object.

@javax.ejb.Entity(access=FIELD)

@javax.ejb.Entity declares a Java class as an entity bean.

The access=FIELD value means the bean's fields are persistent, as in JDO. Unlike JDO, only the bean itself or its children may access the fields. Other classes must use the bean's methods, like getters or setters, to indirectly access the fields. The default access value is PROPERTY, meaning method getters are enhanced.

@Table - naming the table

@javax.ejb.Table specifies the SQL database table name to be used. If @Table is unspecified, Resin will use the class name as the table name.

@javax.ejb.Table(name="ejb3_basic_course")

@Id - marking the primary key

The @Id attribute marks the bean's primary key. The EntityManager.find method looks up a bean instance with the primary key, and relations use the primary key to link beans together.

@javax.ejb.Id (generator=AUTO)
@javax.ejb.Column (name="id")
private int _id;

The optional generator=AUTO specifies automatic generation of primary keys when beans are created. The default NONE does not automatically create primary keys. AUTO generates primary keys depending on the database. Postgres, for example, will use a SEQUENCE, while Resin's built-in database will use an auto_increment IDENTITY.

The optional @Column annotation specifies the SQL column name. The default SQL column for an @Id is "ID".

@Basic - marking a persistent field

The @Basic attribute marks a basic data column like a string or integer or double.

@javax.ejb.Basic 
@javax.ejb.Column (name="course")
private String _course;

@Column - naming the column

The optional @Column annotation specifies SQL column name. For an @Id, the default column name is "ID". For a @Basic field, the default column name is the field name.

Under the covers: bytecode enhancement

Resin processes the bean's class to implement field-enhancement. In practice, this means replacing setting a field with a Resin setter and getting a field with a Resin getter.

public String course()
{
  return _course;
}

For example, Resin would process the above method and produce something like:

public String course()
{
  return __caucho_get_course();
}

Client Servlet

The client servlet queries the database for all courses and lists them. It uses the EntityManager API to create a Query and uses the Query to obtain the results.

CourseServlet.java
public class CourseServlet extends HttpServlet {
  private EntityManager _manager;

  public void setEntityManager(EntityManager manager)
  {
    _manager = manager;
  }

  public void service(HttpServletRequest req, HttpServletResponse res)
    throws java.io.IOException, ServletException
  {
    PrintWriter out = res.getWriter();

    res.setContentType("text/html");

    out.println("<h3>Course Details</h3>");

    Query query = _manager.createQuery("SELECT o FROM Course o");
    
    for (Course course : (List<Course>) query.listResults()) {
      out.println("course: " + course.course() + "<br>");
      out.println("teacher: " + course.teacher() + "<br>");
      out.println("<br>");
    }
  }
}

Course Details

course: Potions instructor: Severus Snape course: Transfiguration instructor: Minerva McGonagall

EntityManager

EntityManager is the primary interface for finding, querying, adding and deleting persistent beans. It is stored in JNDI at java:comp/EntityManager.

public void setEntityManager(EntityManager manager)
{
  _manager = manager;
}

The example uses dependency injection to configure the entity manager. The web.xml will find the EntityManager in JNDI and set it in the servlet before calling the init()

web.xml configuration
<servlet servlet-name="basic" servlet-class="example.CourseServlet">
  <init entity-manager="${jndi:lookup('java:comp/EntityManager')}"/>
</servlet>

Of course, a servlet can also use JNDI directly in its init() method.

Query

Query acts like a PreparedStatement in JDBC. It saves a parsed SQL query and allows for parameters.

Query query = _manager.createQuery("SELECT o FROM Course o");

The SQL used for EJB 3.0 is an enhanced database SQL. The query can return objects directly ("SELECT o") and it can traverse relations ("o.next.data"). In most other respects, it can be thought of as regular SQL.

List list = query.listResults();

The query returns its values with listResults(). Queries which return a single value can use getSingleResult().

Resin Configuration

The Resin configuration is fairly straightforward. Resin needs to start the ejb-server, configure the JDBC data-source, and list the beans that will be used.

WEB-INF/web.xml
<web-app>
  <!-- server configuration -->
  <ejb-server data-source="jdbc/resin">
    <bean type="example.Course"/>
  </ejb-server>

  <servlet servlet-name="basic" servlet-class="example.CourseServlet">
    <init entity-manager="${jndi:lookup('java:comp/EntityManager')}"/>
  </servlet>

  <servlet-mapping url-pattern="/basic" servlet-name="basic"/>
</web-app>

The <ejb-server> configures Resin's EJB support. Each <bean> adds a new bean (entity, session or message-driven.)

The servlet's <init> method uses dependency injection to configure the servlet. Some applications may want to call JNDI directly from within the servlet, although that removes some configuration flexibility.

Try the Tutorial


Tutorials
Tutorials
Transactions
Copyright © 1998-2005 Caucho Technology, Inc. All rights reserved.
Resin® is a registered trademark, and HardCoretm and Quercustm are trademarks of Caucho Technology, Inc.