A plain Hibernate on Z2 sample

Note that Hibernate is used in other samples as well, such as Sample-jta-plain, Sample-jta-spring, and others. This sample shows the minimal things to do to use Hibernate as an implementation of the Java Persistence API (JPA).

This sample is stored in the repository z2-samples.hibernate.basic.

This sample makes use of the Hibernate Add-on and is most likely the best documentation on how to use its supporting functionality. While some of the possibly complex seeming (but only needed once) glue code below is not required when using Spring (for example), as in Sample-spring-hibernate, Sample-springds-hibernate, this sample is most instructive on how Hibernate, Transaction Management, Z2, and the Jetty Web Container integrate with one another while closely sticking to standard descriptors (JPA) and naming (Java EE JNDI/Servlet).

Prerequisites

Z2 has the following Java Version requirements

Z2 Version Min. Java version required Max Java version supported
2.1 - 2.3.1 Java 6 Java 7
2.4 - master Java 8 Java 8

Note: Most samples suggest to use the master branch. You may choose another version branch (please check the respective repository).
Make sure you have a corresponding Java Development Kit (JDK) or Java Runtime Environment (JRE) installed. If in doubt, go to Download Java SE.

Note: Running v2.1-v2.3.1 on Java 8 is supported by specifying

com.zfabrik.java.level=7

(or 6, if that is your desired compilation language level) in <home>/run/bin/runtime.properties. By this the Java compiler version detection does not fall back to a lower level.

You need to run Java DB as network server on localhost. This is explained next.

The application will create a database "z2-samples"

Running a Java DB Network Server

In samples we use the Java DB, i.e. the SQL database implementation that comes with the Java SE Development Kit (JDK) by Oracle (except for Mac OS in which case you have to use Apache Derby). Java DB is the same as the Apache Derby DB - see also the installation how-to.

The instructions below apply to both, there is only a difference in the installation path.

For general information on Java DB go to http://docs.oracle.com/javadb/10.8.2.2/getstart/index.html

To run the Java DB in server mode, which is what we want to do, run

mkdir derby
cd derby
java -jar $JAVA_HOME/db/lib/derbyrun.jar server start

assuming you want to run it in the folder derby. At a second time you can omit the "mkdir" command of course. The environment variable JAVA_HOME is expected to point to your JDK installation folder. When you installed Apache Derby and followed the instructions mentioned above, you have to replace $JAVA_HOME by $DERBY_HOME.

On Windows run

mkdir derby
cd derby
java -jar "%JAVA_HOME%\db\lib\derbyrun.jar" server start

In order to interactively query Java DB, we recommend to use the Data Source Explorer view in Eclipse. But any SQL client that can make use of JDBC drivers should be fine. The driver for Java DB can be found (at the time of this writing) in $JAVA_HOME/db/lib/derbyclient.jar (and similarly on Windows).

Note: If you have problems running Derby due to Security Exceptions, it may be necessary to update your security profile as described in http://stackoverflow.com/questions/21154400/unable-to-start-derby-database-from-netbeans-7-4 (and please make sure you have a good JAVA_HOME and PATH setting).

Alternative: Using the DB-Worker Node Add-on (no separate RDBMS installation required)

you can also use the DB Worker Node Add-on which runs Apache Derby RDBM as a regular z2 worker process, so you don't need to install any extra database software.

How to augment the samples to use the DB Worker node?

You have to add the DB Worker Node Add-on to your samples environment and tell the server to start the DB worker node beside the web worker.
For this you can use the two files attached to this page:

  • dbWorkerAddon.properties - points to the z2 component repository containing the DB Worker Node Add-on
  • home.properties - a slightly changed home layout that launches the DB worker in addition to the web worker

Just download these two files and put them under .../install/z2-samples.XYZ/environment/ - where z2.samples.XYZ must be replaced by the concrete sample name like z2-samples.spring-hibernate

Run the sample

Like all samples, also this sample can be run as in How to run a sample. If you have the database, the fastest way to verify whether it runs is:

mkdir install
cd install 
git clone -b master http://git.z2-environment.net/z2-base.core
git clone -b master http://git.z2-environment.net/z2-samples.hibernate-basic

# on Linux / Mac OS:
cd z2-base.core/run/bin
./gui.sh

# on Windows:
cd z2-base.core\run\bin
gui.bat

When started, go to http://localhost:8080/hibernate-basic. You should see this:

Details

A lot of the things happening here relate to what is explained in How to transaction management.

The assumption of this example is that of a re-use domain module com.zfabrik.samples.hibernate-basic.domain that implements a "Thingy Repository" and is used from a web application that is in another module com.zfabrik.samples.hibernate-basic.web. The domain module exposes the Thingy Repository as a Z2 component that is bound by the Web app as an environment (ENC) variable and injected into the controller filter by the Web container.

The domain module makes use of Hibernate's JPA implementation and integrates with the transaction management provided by com.zfabrik.jta.

Now, step-by-step.

The domain module and its persistence context

The domain module com.zfabrik.samples.hibernate-basic.domain defines a persistence unit "thingies" in java/src.impl/META-INF/persistence.xml, i.e. in its implementation. That makes sense, as the XML file will be looked up with a class loader and we do not intent to retrieve from another module. Or, put differently, the persistence unit is not part of the module's API.

In order to integrate with the built-in transaction management the persistence.xml declares the JTA data source

<jta-data-source>components:com.zfabrik.samples.hibernate-basic.domain/DB</jta-data-source>

and the JTA Platform (Hibernate's transaction management abstraction since v4.3)

<property name="hibernate.transaction.jta.platform" value="com.zfabrik.hibernate.Z2JtaPlatform"/>

The former points to the data source component com.zfabrik.samples.hibernate-basic.domain/DB, while the latter makes sure Hibernate can register with the transaction manager implementation that comes built-in with Z2 (other samples, such as Sample-jta-plain, Sample-springds-hibernate show alternative approaches).

The persistence unit defines only one entity. The Thingy as in Thingy.java. That is an API-exposed type. We use the simplified pattern of exposing persistent objects in the API rather than using Data Transfer Objects (DTOs).

Also, the domain module exposes the interface of the Thingy Repository. This interface is used by the Web application to retrieve, store, and delete thingies.

The implementation of the Thingy Repository, ThingyRepositoryImpl is not a public type. Instead, it is instantiated and held on to via a Z2 component lookup from the Web app on the component com.zfabrik.samples.hibernate-basic.domain/repository.

In ThingyRepositoryImpl, in order to access and re-use the JPA Entity Manager for the persistence unit "thingies" we use EntityManagerUtil from org.hibernate with a Entity Manager Factory that we create upon service instantiation and using the user transaction implementation of com.zfabrik.jta:

public class ThingyRepositoryImpl implements ThingyRepository {
    private EntityManagerFactory emf;

    /**
     * Create the repo
     */ 
    public ThingyRepositoryImpl() {
        /*
         * We switch the context class loader so that Hibernate finds our persistence.xml.
         * We use the EntityManagerUtil so that Hibernate doesn't freak out in a 
         * no-Initial-Context-Factory (but URL for lookup) naming environment.
         */
        this.emf = ThreadUtil.cleanContextExecute(
            this.getClass().getClassLoader(),
            new Callable<EntityManagerFactory>() {
                @Override
                public EntityManagerFactory call() throws Exception {
                    return EntityManagerUtil.createEntityManagerFactory("thingies");
                }
            }
        );
    }

    @Override
    public void store(Thingy thingy) {
        this.em().persist(thingy);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Collection<Thingy> findAll() {
        return this.em().createQuery("select t from Thingy t").getResultList();
    }

    @Override
    public void delete(int id) {
        Thingy t = this.em().find(Thingy.class, id);
        if (t != null) {
            this.em().remove(t);
        }
    }

    //
    // Uses the Entity Manager Util that holds on to EMs created from the passed on EMF
    // while the transaction is still open.
    //
    private EntityManager em() {
        return EntityManagerUtil.getEntityManager(
            IComponentsLookup.INSTANCE.lookup(
                "com.zfabrik.jta/userTransaction", 
                TransactionManager.class
            ),
            this.emf
        );
    }
}

Note that when creating the entity manager factory, we have to make sure the right context class loader is set so that the persistence unit definition will be picked up by Hibernate. This is a general pattern when initializing services in a modular application: You need to distinguish when the service's context matters vs. when the caller's context matters (check out a blog article on that).

We would normally use the JPA class Persistence to create an entity manager factory. Due to HHH-8818 we do need to work around some JNDI issue by using the EntityManagerUtil (see its source code here).

The web module, transaction boundaries, and service re-use

Let's turn to the Web application in com.zfabrik.samples.hibernate-basic.web/web. And let's start with how the Thingy Repository is accessed from the Web app. In this example we do not use Spring or direct lookups, instead we use the Web container provided dependency injection mechanisms. In WebContent/WEB-INF/jetty-env.xml we bind the result of a JNDI lookup for the repository implementation component to the Environment Naming Context (ENC) variable "repos/thingies". This is java EE mechanics. It means that from within the Web app, the repository is available under the JNDI name "java:comp/env/repos/thingies":

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  <New id="thingyRepository" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg>repos/thingies</Arg>
    <Arg>
      <New class="javax.naming.LinkRef">
        <Arg>components:com.zfabrik.samples.hibernate-basic.domain/repository?type=com.zfabrik.samples.hibernate_basic.thingies.ThingyRepository</Arg>
      </New>
    </Arg>
  </New>
</Configure>

See also Jetty JNDI.

Anyway. Now, in the ControllerFilter we inject the Thingy Repository like this:

public class ControllerFilter implements Filter {

    // inject thingies repository (see WEB-INF/jetty-env.xml)
    @Resource(name="repos/thingies")
    private ThingyRepository thingyRepository;

...
}

Alternatively, if you think this is a little overkill, you might as well use a direct lookup, either with JNDI using the name in the XML or via Z2's component lookup

IComponentsLookup.INSTANCE.lookup("com.zfabrik.samples.hibernate-basic.domain/repository",ThingyRepository.class);

Finally a word on transaction management. Transaction boundaries are controlled by the TransactionFilter contained in the sample. We make use of TransactionUtil from com.zabrik.jta to wrap the actual web app request in a transaction:

@Override
public void doFilter(final ServletRequest sreq, final ServletResponse sres,    final FilterChain chain) throws IOException, ServletException {
  HttpServletRequest req = (HttpServletRequest) sreq;
  if (req.getDispatcherType()==DispatcherType.REQUEST || req.getDispatcherType()==DispatcherType.ASYNC) {
    try {
      TransactionUtil.run(
        (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction"),
        new Callable<Void>() {
          public Void call() throws Exception {
            chain.doFilter(sreq, sres);
            return null;
          }
        }
      );
    } catch (Exception e) {
      throw new ServletException(e);
    }
  } else {
    chain.doFilter(sreq, sres);
  }
}

Finally note that we retrieved the transaction manager via the standard Java EE JNDI name java:comp/UserTransaction. Z2 uses Jetty as its Web container implementation. In order to have Jetty bind the transaction manager, we configure the Web server in environment/webServer/jetty.xml to retrieve the built-in transaction manager:

...

    <New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction">
        <Arg>
            <New class="com.zfabrik.tx.UserTransaction">
            </New>
        </Arg>
    </New>
...

How this sample makes use of MVNCR

This sample in conjunction with the Hibernate add-on is good example on how to use the Maven component repository (see How to Access a Maven Repository).

The situation is this:

  • The add-on (the Hibernate add-on in this case) defines the artifacts required but may not define the actual artifact repository to use. After all it may be used with a locally hosted artifact repository.
  • The solution environment (in this case this sample) may define the actual artifact repository but it should not need to repeat all the details on the actual artifact names and versions

To resolve this we use Maven component repository declarations and Maven component repository fragment declarations.

  • The repository declared as part of the sample in environment/mavenDefault has all the information on where to get artifacts from, while
  • the fragment declared in the add-on at org.hibernate/mvnFragment declares the dependency roots it needs to have resolved from the (yet unknown - from the perspective of the add-on) MVNCR environment/mavenDefault.

hibernate-basic.png (37 KB) Henning Blohm, 18.09.2012 10:06