EJB3

Persistence Using Enterprise Java Beans

Some highlights of the new EJB3 standard:

  • Exploits Java 5 features such as annotations and generics
  • Multiple containers (Glassfish, JBoss, Oracle at least)
  • Multiple O-R implementations (Hibernate, Toplink)
  • Database independent
  • Compile-time check of configuration
  • Uses dependency injection via annotations
  • Virtually no XML
  • Plain old Java objects (POJO) — no special base classes needed
  • Eliminates need for separate data transfer objects
  • Uses detached object technique
  • Entity inheritance and discriminators using Java extends
  • Easy Primary Key designation
  • Embeddable objects
  • Option to auto-generate schema from Java, including updates
  • EJB-QL query language
  • Simple web services creation

A simple example, ignoring healthcare, shows many of these concepts.

The Domain

In this simple example, a person can optionally be a member of a household which has an address. If not, they are considered homeless. Any number of people can be associated with a household.

The Application

A stateless session bean running in an application server which in turn is connected to a database serves requests from several stand alone, command-line programs. These simple client programs communicate with the server via RMI asking it to create, manipulate and display entities.

The Server View

This section will walk though key aspects of the server. The Client View follows.

Entity Beans

Entity beans somewhat correspond to database tables. Entity objects look like a regular Java bean: A no-argument constructor, get and set methods for the attributes. The class must implement the Serializable interface if it might be used in remote communication (in our case they will).

@Entity@Table(name = "PERSON", schema="simple")public class Person implements Serializable {

The @Entity annotation alerts the container to provide object-relational mapping for this object and enables the annotated object, person in this case, to be used in queries.

The @Table annotation has defaults so that it can be shortened to just @Table but we want to be explicit about the table and schema representations in the database.

Primary Keys

While EJB entities support natural and complex primary keys, we will keep it simple: all primary keys will be surrogate IDs, with meaningless sequential numbers generated by the container and automatically stored in the entity for us. We name this attribute ID and will provide a setter and getter, but will only use the getter method.

@Id @GeneratedValue
private long id;
Attributes

Entity Bean attributes are defined normally. They typically, although not required, have corresponding get and set methods while the attribute itself usually has private scope to provide encapsulation.

The object-to-relational mapping tool uses annotations, new for Java 5, to provide the hints needed to do its work. The BLOB column is notable. Since this column is potentially large and may not be needed in all cases, it has a fetch type of LAZY meaning that it will not be fetched from the database until it is needed. The default fetch type is EAGER.

 @Column( name="PERSON_NAME")
	private String name;

 @Column( name="SORT_NAME")
	private String sortName;

 @Lob
 @Basic(fetch=FetchType.LAZY)
 @Column(name="photo")
 private byte[] photo;
Relationships

Relationships are defined as usual, and annotated to inform the container how to map the relationship in the database.

Many-to-one is straightforward. In this case, the Person object has a relationship with a household which is covered by the @ManyToOne annotation.

 /**
  * The person can be part of a household.
  */
 @ManyToOne
 private Household household; 

On the other side of this relationship, in the household class, is a collection.

 @OneToMany(mappedBy = "household", cascade=CascadeType.ALL) private Set<Person> people = null;

The @OneToMany annotation automatically populates the collection (a set). There is no separate query needed. The cascade modifier means all operations are cascaded to the many side of the relationship. Simply put, it means that there is a household column in the person table, not a collection of persons in the household table, which is what you would expect to see in a relational database schema definition.

In fact, for those interested, here’s the DDL that is generated under the covers. If you notice the photo column, its datatype is oid. This is peculiar to the way PostgreSQL stores blobs. But we don’t need to be concerned about that because the O-R mapper takes care of variations among database products.

CREATE TABLE "simple".person(  id int8 NOT NULL,  person_name varchar(255),  household_id int8,  sort_name varchar(255),  photo oid,  CONSTRAINT person_pkey PRIMARY KEY (id),  CONSTRAINT fk8c768f5592cfc0b5 FOREIGN KEY (household_id)      REFERENCES "simple".household (id) MATCH SIMPLE      ON UPDATE NO ACTION ON DELETE NO ACTION)

Notice in this example that the contents of the set are specified and constrained by the generic notation <Person>. This is a significant improvement over previous versions of Java that usually required casting the contents of a collection and provide no type checking of the list’s contents.

The collection is, by definition, a set. When creating a new object, you can add methods that support the collection, such as:

 public Set<Person> getPeople() {
    if (people==null) {
        people = new HashSet<Person>( );
    }
    return people;
 }

 public void addPerson(Person person) {
    getPeople().add(person);
    person.setHousehold(this);
 }

 public void setPeople(Set<Person> people) {
    this.people = people;
 } 
Embeddable Objects

In our simple application, we define a separate address class to be used in a household entity, anticipating that other entities will need addresses as well. But we do not want to store the address in a separate database table (although we could). Looking at the household entity, we see a normal attribute declaration with an @Embedded attribute.

@EmbeddedPrivate Address address;

What it means is that the persistence manager should add the attributes of address to the underlying household table simply as more columns and not as columns in a separate table. If we look at the address bean, it looks similar to a normal @Entity bean. But instead of @Entity, the class has the @Embeddable annotation which indicates that there will be no separate table for it. The attributes in @Embeddable address have the same annotations as an @Entity would have:

@Embeddable
public class Address  implements Serializable {
    // Version number for Address
    private static final long serialVersionUID = 1L;

    @Column( name="LINE1")
    private String line1;

    @Column( name="LINE2")
    private String line2;

    @Column( name="CITY")
    private String city;

    @Column( name="STATE")
    private String state;

    @Column( name="POSTAL_CODE")
    private String postalCode;

    @Column( name="COUNTRY")
    private String country;

Notice that the address class, in order to participate in a serialization of the class it belongs to, must also implement serializable.

Even though we don’t have to worry about it, the resulting DDL will look something like this, depending on the O-R tool and database. Notice that all the fields have a length of 255 because we didn’t include a preference in the @Column annotation:

CREATE TABLE "simple".household(  id int8 NOT NULL,  line1 varchar(255),  line2 varchar(255),  city varchar(255),  state varchar(255),  postal_code varchar(255),  country varchar(255),  CONSTRAINT household_pkey PRIMARY KEY (id))
Life-Cycle Callbacks

A simple annotation can be used to declare that a specific method be called just before the object is persisted (there are similar annotations for just after construction, just after persistence, etc.). In this case, because we have a name attribute, we need a method that maintains an all caps version of the name for efficient in sorting and indexing. For example, “Tammy Wilson” would be stored in a second column as “TAMMY WILSON.” In this example, the sortName attribute has no set method, only a get method.

@PrePersist
    public void populateSortName() {
        if (getName()!=null) {
            sortName = getName().toUpperCase();
        } else {
            sortName = null;
        }
    }
 
The Session Bean

A session bean receives requests, in the case of this example, from remote programs, and carries out those requests in the context of a transaction. It communicates with the persistence manager to perform create, read, update, and delete (CRUD) operations. While not shown in this example, session beans can and often do communicate with each other. When doing so, they remain in the same transaction context by default. For this reason, methods in a session bean should never make assumptions about the autonomy of their part in a larger transaction. Simple rule: Avoid putting explicit commit or rollback operations in a session bean.

  @Local(PeopleLocal.class)
  @Remote(PeopleRemote.class)  @WebService  public @Stateless class PeopleBean implements PeopleLocal, PeopleRemote {

The most important part about the annotations on this normal class declaration of the PeopleBean is what you don’t see: There is no other declaration needed to make this is a stateless session bean. No XML files to fill out. No wizards are needed to provide supporting Java code. The PeopleLocal and PeopleRemote interfaces are simple and not worth showing.

The reason separate interfaces are used (since EJB2) is that the session bean behavior might be different knowing that the client is calling over a network connection rather than in the same memory space. It certainly has a big impact on performance. The semantics are:

  • Local interface: call-by-reference (only one instance of each parameter exists)
  • Remote interface: call-by-value (a copy of each parameter is made)

There’s also an optional @WebService annotation. This triggers the automatic creation of a WSDL and registers the session bean with the container as a web service end-point. Each method you want to expose as an end-point should have the @WebMethod annotation.

Dependency Injection

In this example, the persistence context in the session bean is wired up automatically. The container, upon seeing the @persistenceContext annotation, sets the value of the attribute without us doing anything. We can just assume it is set.

/**
 * Wiring is automatic in EJB3: The container sets this value for us. */ @PersistenceContext private EntityManager em;

Other kinds of wiring is usually done as well but we will keep it simple for this example.

Constructing and Persisting an Entity

While you are free to use the factory pattern, there is no requirement to do so when creating an entity bean. A simple new will do it. Use the get/set methods as usual to make the object look the way you want it to look.

    Person person = new Person();    person.setName( "Bill" );
    ...

But the object doesn’t get into the database with just a new. If we were doing this on the server, all that would be needed to persist the object in the database is:

em.persist( person );

And that is exactly what will happen in the addPerson method of the PersonBean class. But in this example, the client creates the object. It then passes the new person object to the PersonBean, a stateless (thus we don’t care which instance handles the request) session bean on the server by calling a method called addPerson on an interface called PeopleRemote. In short, PeopleRemote is where the remote proxy is created that talks to the server-side implementation of the PeopleRemote interface. Since do not have to do any work to setup this proxy, we will not describe it further.

peopleRemote.addPerson();
Detached Entities

Once persisted, the new object is attached to the database: The entity manager is responsible for the lifecycle and distribution of that object. In fact, this point is critical to the difference between EJB 2 and EJB 3. In EJB 2, the association between an entity object and the database was so close that the entity could not move from where it was instantiated. That caused a major problem: Client programs could interact with the entity object remotely, but that would certainly be a performance killer and also affected scalability because the lifecycle of an entity might have to be extended just to handle the relatively slow interactions. The alternative was to create a data transfer object, a rendition of the entity bean used to transfer information between client and server. Duplicating every entity bean in this way certainly has disadvantages.

But that has all changed with the introduction of detachment. When an entity is fetched from the database, the persistence manager now allows that entity to leave the JVM and allows it to live beyond the end of the transaction from which it came. Thus, the persistence manager gives up control, and allows the object to be serialized and used in any form needed without being under the control of the persistence manager. That is detachement.

To get that object to later join back up with the database, perhaps updating the contents of the database, use the persistence manager’s merge method. Merge means that the persistence manager should coordinate changes made to that entity with the database and with any other object that may have already been associated with that row in the database. The entity bean is thus reattached to the database. In this way, an entity can be fetched from the database in one transaction and returned to the database in another transaction.

public void addHousehold(Household household) {
    em.merge( household );
}

The addHousehold method is shown here to illustrate the power of the merge method. First, merge may have determined that the object being merged is actually a new object (its ID will be null) to it will do an insert instead of an update. It will also look at the people collection that is part of this object and merge each of them as well. Therefore, if we happen to modify a person as we add them to the household, or a new person is added directly to the household, then that change will also be accounted for without any explicit action.

Optimistic Locking

In the previous example, there is a risk that between the time of the query and the time of the update the object may have changed. The pessimistic approach is to put a lock on the object so no one else can do the same. A much more efficient technique is to simply verify that the object hasn’t changed since it was read. Since the chances are usually small that an intervening event will have occured, the lock is avoided. EJB3 supports optimistic locking and allows the user to specify the technique to check for intervening updates. Essentially, either a version number or a timestamp is compared between the row currently in the database and the one that was previously read. A much less efficient technique can also be used, which is to compare the entire contents of the object.

The version number technique is preferred over the timestamp technique because two actions can occur within a single clock tick, and if the system time is adjusted it can cause duplicate timestamps. The container does the checking automatically.

Packaging

The packaging process for an EJB-based application is quite simple. While there are wizards to help put together ear files, the EJB 3 ear files are quite straightforward. The following illustrates the structure of the ear file, most of which is actually a jar file containing the java classes we’ve created.

 

+- simple.ear
    +- simpleEJB (jar)
       +- org.tolven.simple
          +- PersonLocal.java
          +- PersonRemote.java
       +- org.tolven.simple.bean
          +- PeopleBean.java
       +- org.tolven.simple.entity
          +- Address.java
          +- Household.java
          +- Person.java
       +- persistence.xml
    +- application.xml
+- simple-ds.xml

There are just two small xml files to setup. They rarely need to change.

application.xml defines the application as a whole. If the application included a web application (WAR) module, it would also be mentioned here, but in our case all we have is the one jar file with the EJBs in it.

<?xml version="1.0" encoding="UTF-8"?><application version="5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application_5.xsd">  <display-name>Simple Application</display-name>  <module>    <ejb>simpleEJB.jar</ejb>  </module></application> 

The persistence.xml file associates the persistence context used in the session bean(s) with the datasource. This file must be on the class path and so we put it in the simpleEJB.jar file.

<?xml version="1.0" encoding="UTF-8"?><persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">  <persistence-unit name="em" transaction-type="JTA">    <jta-data-source>java:/SimpleDS</jta-data-source>    <properties>      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>      <property name="hibernate.show_sql" value="true"/>      <property name="hibernate.hbm2ddl.auto" value="update"/>    </properties>  </persistence-unit></persistence> 

You’ll notice that the persistence.xml file contains the binding to the persistence unit used in the session bean. It specifies the transaction architecture to use (JTA), where to find the datasource via JNDI and some properties for the mapping tool to use. In the actual code, I include some TopLink properties as well. They can be mixed together so you don’t need separate configurations if you support more than one O-R tool. In this case, we would like Hibernate to provide mapping to the PostgreSQL dialect, that it should show SQL it prepares, and that it should auto-update database schema definitions based on the Java entity bean definitions.

The simple-ds.xml file is not part of the ear file; it is deployed separately, usually only once. It represents the pool of JDBC connections to the database. It is where the actual jdbc connection parameters are specified. (The security criteria in this case just uses a modest plaintext username and password.)

<datasources>  <local-tx-datasource>    <jndi-name>SimpleDS</jndi-name>    <connection-url>jdbc:postgresql://localhost/postgres</connection-url>    <driver-class>org.postgresql.Driver</driver-class>    <user-name>postgres</user-name>    <password>postgres</password>  </local-tx-datasource>  </datasources> 
Deployment

Deployment is the point when the logical schema defined in Java entity Beans “hits the database.” The entity definitions are materialized or updated in the database. The container “wires up” any dependencies, which in this example means to set the em variable to the instance of the persistence context it has created.

Client View

Now that the server is complete and running, we can look at what is going on in the client code. Each of the small client programs starts out the same, by finding and connecting to a session bean in the server.

InitialContext ctx = new InitialContext();
// Bind to the remote session bean interface in the running server via JNDI/RMI
PeopleRemote people = (PeopleRemote) ctx.lookup("simple/PeopleBean/remote");

JNDI will need a little help to determine where to connect, so a client-side configuration file (which must be on the classpath) will direct the request to the correct server. In our case, localhost as shown in this jndi.properties file:

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactoryjava.naming.provider.url=jnp://localhost:1099java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

Once the remote proxy is established, we interact with the session bean as if it were local; however, remember that each of these interactions involves serialization and a network round trip so a remote interface is not intended for fine-grained, attribute-by-attribute, interactions.

In the examples below, we show both the client and server side code so you get an idea of what is actually going on. Also, since we do not impose a transaction boundary explicitly, each call to the server is a separate transaction. No code needs to be written to support this behavior.

The entity beans we use on the client are the exact same classes we used on the server. The only difference is that on the client the persistence annotations are ignored. The client is just working with a plain Java object, not bound to the database. (In the case of a local interface, it might be bound to the database, but we don’t need to worry about that in either case).

Client1

Our first client program simply creates 50 person objects and gives them, one at a time, to the people session bean we bound to above, asking it add each one to the database.

    for (int x = 0; x < 50; x++) {        Person person = new Person();        person.setName( "Bill " + x );        people.addPerson(person);    }

The server side code for addPerson is:

/** * Persist the supplied Person object for the first time */public void addPerson(Person person) {    em.persist(person);}
Client2

Client2 starts by asking the server to do a query to find all people that are homeless (household = null) and return the results as a list of people. Interactions with the server are bolded in the following snippet.

    List<Person> list = people.findHomelessPeople();    Household household = null;    for (Person p : list ) {        if (household==null) {            household = new Household();            Address address = new Address();            address.setCity("Boca Raton");            address.setState("FL");            address.setCountry("USA");            household.setAddress(address);        }        household.addPerson(p);        if (household.getPeople().size() > 2 ) {            people.addHousehold(household);            household = null;        }    }    if (household!=null) people.addHousehold(household);

The server side code for findHomelessPeople is:

/** * Query the database for people not associated with a household   * and return them in a list. */public List<Person> findHomelessPeople() {    Query query = em.createQuery( "SELECT p FROM Person p WHERE " +
        "p.household IS NULL");    return query.getResultList();}

The server side code for addHousehold is:

/** * Create the household. As a side effect, this will also * update persons which now have a reference to this household. * Notice that Merge us used for this purpose. */public void addHousehold(Household household) {    em.merge(household);}
Client3

Client3 asks the server to return a list of all people, not just homeless people. It prints out their names. It also updates every third name to Sam.

List<Person> list = people.findPeople();for (Person p : list ) {    System.out.format("Person %d=%s\n", p.getId(), p.getName());    // While we at it, update every third person    if (p.getId()%3==0) {        p.setName( "Sam");        people.updatePerson(p);    }}

The server code for findPeople is:

/** * Query the database for all people and return them in a list. */public List<Person> findPeople() {    Query query = em.createQuery( "SELECT p FROM Person p");    return query.getResultList();}

The server-side code for updatePerson is:

/** * Ensure that the supplied Person object that came  * from persistence is updated if needed. */public void updatePerson(Person person) {    em.merge(person);}
		  
Client4

Client4 uses session bean (server-side) methods we’ve already described above, but it goes a bit further in order to show that the relationship between objects is also handled by EJB. In this example, we find all people. If a person is part of a household and that household has an address, we display part of the address. Otherwise, we display that the person is homeless.

// Ask the server to do the query and return resultsList<Person> list = people.findPeople();for (Person p : list ) {    if (p.getHousehold()==null || p.getHousehold().getAddress()==null) {        System.out.format("Homeless Person %d=%s\n",
                p.getId(), p.getName());        } else {        System.out.format("Person %d=%s @ %s, %s\n",                 p.getId(),                 p.getName(),                 p.getHousehold().getAddress().getCity(),                 p.getHousehold().getAddress().getState());        }}

Further Resources

Browse Source Code (simpleEJB and simpleEJBClient)

CVS

Sun Java EE Tutorials

Sun Java EE Documentation

JBoss EJB3 Site

 

Back to the top
Back to the top

In Production

The Tolven Platform is rapidly becoming the most widely adopted open source solution for healthcare information technology globally. Tolven clients in Europe, North America, and Asia are leveraging the breadth of solutions the Tolven technology can support to serve their needs.

See sample client descriptions

The Tolven Platform

The Tolven Platform takes advantage of a broad, flexible, and open source architecture that gives healthcare and life sciences professionals as well as patients the information they need in an open and extensible solution. The Tolven Platform and applications have global applicability.

Read more