A sample using Hibernate and Spring on Z2

This sample is very similar to Sample-hibernate-basic but differs in that we use the Spring framework throughout...

  • for assembly within the modules and to wire services between modules
  • for declarative transaction demarcation
  • for JPA entity manager injection

This is another practical application of How to Spring.

This sample is stored in z2-samples.spring-hibernate.

Check out How to transaction management for more infos on transaction management on Z2. See related examples

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 it

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.spring-hibernate

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

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

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

Details

Similar to Sample-hibernate-basic, the assumption of this example is that of a re-use domain module com.zfabrik.samples.spring-hibernate.domain that implements a "Thingy Repository" and is used from a web application that is in another module com.zfabrik.samples.spring-hibernate.web. The domain module exposes the Thingy Repository as a Z2 component - from a Spring application context defined bean - that is imported into the application context of the Web application and injected into the controller filter by Spring. The controller uses declarative transaction demarcation.

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

The domain module and its persistence context

The domain module com.zfabrik.samples.spring-hibernate.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.spring-hibernate.domain/DB</jta-data-source>

and the Transaction Manager Lookup

<property name="hibernate.transaction.manager_lookup_class" value="com.zfabrik.hibernate.TransactionManagerLookup" />

The former points to the data source component com.zfabrik.samples.spring-hibernate.domain/DB, while the latter makes sure Hibernate can register with the transaction manager implementation.

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).

The application context of the module is defined in java/src.impl/META-INF/applicationContext.xml and looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xsi:schemaLocation=" 
    http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
    http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-3.0.xsd  
    http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
    http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- annotation based config -->
    <context:component-scan base-package="com.zfabrik.samples.spring_hibernate" />
    <context:annotation-config />

    <!-- EntityManager injection -->
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <!-- The actual EMF we use -->
    <bean id="entityManagerFactory"    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="thingies" />
    </bean>

</beans>
In short:
  • We make sure we can use annotations
  • We enable entity manager injection
  • We initialize the entity manager factory from Spring

In the implementation class ThingyRepositoryImpl we make use of these capabilities and declare a Spring bean "thingyRepository":

@Repository("thingyRepository")
public class ThingyRepositoryImpl implements ThingyRepository {
    @PersistenceContext
    private EntityManager em;

    @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);
        }
    }
}

In order to expose that bean as a Z2 component for re-use from other modules, we declare a component com.zfabrik.samples.spring-hibernate/repository:


com.zfabrik.component.type=org.springframework.bean

#
# Expose Spring defined data source
#

#
# the context that defines the bean (more than one
# bean can be exposed like this)
#
bean.context=com.zfabrik.samples.spring-hibernate.domain/applicationContext

#
# the bean name
#
bean.name=thingyRepository

that is based on the application context component com.zfabrik.samples.spring-hibernate/applicationContext:


com.zfabrik.component.type=org.springframework.context

#
# context config location is where the context is 
# actually defined. 
#
context.contextConfigLocation=classpath:META-INF/applicationContext.xml

See also How to Spring for more details on these component types.

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

Let's turn to the Web application in com.zfabrik.samples.spring-hibernate.web/web. This one is also Spring configured. In contrast to the service module, its application context is not initialized from a Z2 component but rather from the Web app context (see web/WebContent/WEB-INF/web.xml). It is stored in web/WebContent/WEB-INF/applicationContext.xml and looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:security="http://www.springframework.org/schema/security" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
    http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-3.0.xsd  
    http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
    http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">

    <!-- Annotation Support -->
    <context:component-scan base-package="com.zfabrik.samples.spring_hibernate" />
    <context:spring-configured />
    <context:annotation-config />        

    <!--  
    This binds to java:comp/UserTransaction, which is ok in a Web app and considering
    that we configured Jetty JTA (see the transaction manager how-to in the Z2 Wiki and check environment/webServer/jetty.xml)
    -->

    <tx:jta-transaction-manager/>

    <!-- outside of a web app we would bind to com.zfabrik.jta transaction manager like this

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="userTransaction">
            <bean class="com.zfabrik.tx.UserTransaction"/>
        </property>
    </bean>
     -->

    <!-- make sure we can use @Transactional with the Spring aspect -->
    <tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>

    <!-- import external services -->
    <bean id="thingyRepository" class="com.zfabrik.springframework.ComponentFactoryBean">
        <property name="componentName"  value="com.zfabrik.samples.spring-hibernate.domain/repository" />
        <property name="className"  value="com.zfabrik.samples.spring_hibernate.thingies.ThingyRepository" />
    </bean>

</beans>

In short:

  • We enable annotation based configuration
  • We make the transaction manager available (for in-depth details see How to transaction management)
  • We enabled annotation based transaction demarcation (i.e. the use of @Transactional)
  • We import the Thingy Repository as a bean into this context.

The ControllerFilter is configured by Spring, although it is instantiated by the Jetty Web container. That is happening because we use the Spring aspect (see How to Spring once more) and it is annotated with @Configurable. We let Spring inject the Thingy Repository and we mark the doFilter method as transactional. Here is its skeleton:

@Configurable
public class ControllerFilter implements Filter {

  @Autowired
  private ThingyRepository thingyRepository;

  @Transactional
  public void doFilter(ServletRequest sreq, ServletResponse sres,    FilterChain chain) throws IOException, ServletException {

    // do some work here

  }

  @Override
  public void init(FilterConfig cfg) throws ServletException {}

  @Override
  public void destroy() {}
}

A final word

A lot of what happens here requires the right libraries to be available in the sample modules. These are provided via the references in the z.properties files in the respective Java modules.
In other words: There is some non-trivial mechanics going on here that - in the long run - you should be aware of and try to read carefully through How to Spring. As a result you get a lot of coding and modularization convenience in the combination of Spring and Z2.

spring-hibernate.png (37.5 KB) Henning Blohm, 18.09.2012 10:10