JPA with CUBA


As part of the EJB 3 specification, the Java Persistence API has been released as a convenient and compatible way for accessing SQL databases in JEE environments. CUBA also suppports this API - not by implementing it by itself but by integrating existing JPA provider toolkits. In an EJB 3 environment, CUBA works with the application server's JPA provider while the embedded container requires the specification of the provider toolkit in a persistence descriptor. The distribution contains an example for using the open-source toolkit Hibernate as JPA implementation.

The Java Persistence API itself will not be explaind here. For an introduction see the JPA specification and related documentation.

JPA is not supported for EJB 2.1 - references to JPA interfaces like javax.persistence.EntityManager are not accepted by CUBA's generator tools in EJB 2.1 mode. The decision for a particular persistence management approach should therefore consider if EJB 2.1 can be excluded from the relevant runtime  environments. Another important issue is wether compatibility in mapping entity modells to database modells is of interest. The different JPA implementations in different application servers may slightly vary in their mapping techniques and show different behaviour in special situations which are not exactly defined by the JPA specification (e.g. the behaviour without a transaction context). For a maximum of compatibility it is therefore recommended to rely on persistence managers which support all runtime environments in a compatible way and are independend from server vendors. Examples for using the open-source O/R mappers Hibernate, PriDE, and OJB are available from the CUBA website and are part of the examples of the CUBA delivery.

JPA can be used directly without being wrapped in any CUBA-defined compatibility interfaces. To tag a class as an entity type, it gets the annotation @javax.persistence.Entity associated:

@javax.persistence.Entity
public class CustomerEntity implements java.io.Serializable {
    private String id;
    private String firstname;
    private String lastname;
   
    //...
}

The requirement of implementing interface java.io.Serializable is part of the JPA specification. Not all JPA providers actually rely on this detail as long as the instances are not transfered to remote locations but are used inside the container only. An EntityManager is optained by letting the container inject it into the component which needs to access it, e.g.

public class CustomerDAOImpl implements CustomerDAO {

  @javax.transaction.PersistenceContext(unitName="customer")

  EntityManager em;

}

The specification of the unitName is mandatory in CUBA at the moment, even of the application contains only a single unit. According to the standard the unit description is provided in a file META-INF/persistence.xml, where the content depends on the runtime environment which the unit is used in. For a deployment in an EJB 3 container it is usually sufficient to provide a minimal descriptor because many details are implicitly specified by the integration of the JPA provider in the application server. The following example shows such a minimal unit description for the deployment in a JBoss application server 4.2 with a JPA implementation based on Hibernate:

<?xml version="1.0" encoding="UTF-8"?>
<persistence>
  <persistence-unit name="customer">
    <jta-data-source>java:/DefaultDS</jta-data-source>
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
    </properties>
  </persistence-unit>
</persistence>

The specified DataSource must be configured in the application server. In case of a JBoss server, the name "java:/DefaultDS" refers to an HSQL database which is configured in the server by default for test purposes. If there are no entity classes listed in the file, the container scans the deployed JAR and EAR files for classes annotated with @javax.persistence.Entity. The property hibernate.hbm2dll.auto with value  "create-drop" causes the creation of database tables for all entity classes at deployment time. This configuration is of course only reasonable for training purposes. Both configurations should only be understood as illustration examples which usually look different in productive systems and vary for different server vendors and JPA providers. JBoss and Hibernate are both open source tools which you can play around with to become familiar with CUBA's JPA support.

To use JPA in CUBA's embedded container, the persistence.xml must specify the JPA provider to use. Additionally there are usually a few more properties with configuration details required. A central point is the configuration of a class to connect the JPA provider to the container's transaction manager. The following persistence.xml shows an example for using the JPA implementation of Hibernate 3.2.6 as a provider in the embedded container.
(Users of JBoss 4.2 or lower must take care when playing around with JPA in EJB and wired mode both at a time: Hibernate 3.2.6 includes some libraries which are not compatible with some of the client libraries of the JBoss application server. It mus therefore be avoided that the conflicting libraries are both on the classpath of the client.)

<?xml version="1.0" encoding="UTF-8"?>
<persistence>
  <persistence-unit name="customer">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>
java:/DefaultDS</jta-data-source>
    <jar>customer-jpa.jar</jar>
    <properties>
      <property name="hibernate.dialect"
        value="org.hibernate.dialect.PointbaseDialect" />

      <property name="hibernate.transaction.manager_lookup_class"
        value="jpahibernate.CubaTransactionManagerLookup" />

      <property name="hibernate.hbm2ddl.auto" value="update" />
    </properties>
  </persistence-unit>
</persistence>

The specified connector class jpahibernate.CubaTransactionManagerLookup above is part of the JPA example in the CUBA distribution and consists only of a few lines of code. The specified provider is an implementation from the Hibernate distribution which is designed for use in EJB environments. This is the case because CUBA's embedded container internally works with JTA standard interfaces and after all can be understood as a managed environment like a JEE server. It should therefore usually be very easy to connect any other JPA providers with CUBA. The refered DataSource musst be configured in the file wired-application.xml as it is described in chapter Database Access. The value "create" or "create-drop" for property hibernate.hbm2ddl.auto ist usually not reasonable for the embedded container as it causes the creation of database tables with every programm start. The value "update" allows to keep the tables and the data alive as long as the entity model is not modified - but these are hibernate-specific details which are not supposed to be explained in detail here. An important part is the specification of the JAR file which the provider is supposed to scan for entity classes. As an alternative, the <class> element allows to explicitely specify all entity classes which are part of this unit.

The EntityManagers provided by the embedded container are container-managed and transaction-scoped and are accordingly simple to use as explained in the JPA specification for EJB containers. The complicated system-level work for JPA applications in non-managed environments with self-managed transactions and EntityManagerFactories can completely be ommited. The following example shows a JPA-based implementation of a data access object with the same functionality as in the other examples for database access in the CUBA distribution:

@Stateless(name="CustomerDAO")
public class CustomerDAOImpl implements CustomerDAO {

    @PersistenceContext(unitName="customer")
    public EntityManager em;
    
    public CustomerEntity find(String id) {
        return em.find(CustomerEntity.class, id);
    }

    public void create(CustomerEntity entity) {
        em.persist(entity);
    }

}


The example code above is available under examples/jpa.


Home Introduction Javadoc