Project

General

Profile

Sample-hibernate-basic » History » Revision 7

Revision 6 (Henning Blohm, 16.09.2012 19:31) → Revision 7/32 (Henning Blohm, 17.09.2012 16:57)

h1. 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":http://de.wikipedia.org/wiki/Java_Persistence_API).  

 This sample is stored in the repository "z2-samples.hibernate.basic":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic.  

 h2. Prerequisites 

 You need the *z_tx_tests* database on a local MySQL database system. Start the MySQL client as the root user and run: 

 <pre><code class="SQL"> 
 create database z_tx_tests; 
 grant all on z_tx_tests.* to tx@localhost identified by 'tx'; 
 </code></pre> 

 h2. 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: 

 <pre><code class="ruby"> 
 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 
 </code></pre> 

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

 h3. 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":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/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 <code>persistence.xml</code> declares the JTA data source  

 <pre><code class="xml"> 
 <jta-data-source>components:com.zfabrik.samples.hibernate-basic.domain/DB</jta-data-source> 
 </code></pre> 

 and the _Transaction Manager Lookup_  

 <pre><code class="xml"> 
 <property name="hibernate.transaction.manager_lookup_class" value="com.zfabrik.hibernate.TransactionManagerLookup" /> 
 </code></pre> 

 The former points to the data source component "com.zfabrik.samples.hibernate-basic.domain/DB":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/DB.properties, while the latter makes sure Hibernate can register with the transaction manager implementation.  

 The persistence unit defines only If everything would happen inside one entity. The Thingy as in "Thingy.java":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/java/src.api/com/zfabrik/samples/hibernate_basic/thingies/Thingy.java. That is an API-exposed type. We use module, 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":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/java/src.api/com/zfabrik/samples/hibernate_basic/thingies/ThingyRepository.java. This interface is used by the Web application retrieve, store, and delete thingies. 

 The implementation of the Thingy Repository, "ThingyRepositoryImpl":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/java/src.impl/com/zfabrik/samples/hibernate_basic/impl/thingies/ThingyRepositoryImpl.java 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":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.domain/repository.properties. 

 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*: 

 <pre><code class="java"> 
 public class ThingyRepositoryImpl implements ThingyRepository { 
	 private EntityManagerFactory emf; 

	 public ThingyRepositoryImpl() { 
		 //  
		 // initially create the EMF for this domain 
		 // 		
		 this.emf = ThreadUtil.cleanContextExecute( 
			 this.getClass().getClassLoader(),  
			 new Callable<EntityManagerFactory>() { 
				 public EntityManagerFactory call() throws Exception { 
					 return Persistence.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 
		 ); 
	 } 
 } 
 </code></pre> 

 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 structure could 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. kept even simpler.