Project

General

Profile

Sample-hibernate-basic » History » Version 10

Henning Blohm, 18.09.2012 10:06

1 1 Henning Blohm
h1. A plain Hibernate on Z2 sample
2 2 Henning Blohm
3 3 Henning Blohm
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). 
4 4 Henning Blohm
5 5 Henning Blohm
This sample is stored in the repository "z2-samples.hibernate.basic":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic. 
6
7
h2. Prerequisites
8
9
You need the *z_tx_tests* database on a local MySQL database system. Start the MySQL client as the root user and run:
10
11
<pre><code class="SQL">
12
create database z_tx_tests;
13
grant all on z_tx_tests.* to tx@localhost identified by 'tx';
14
</code></pre>
15
16
h2. Run it
17
18 6 Henning Blohm
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:
19 5 Henning Blohm
20
<pre><code class="ruby">
21
mkdir install
22
cd install 
23
git clone -b master http://git.z2-environment.net/z2-base.core
24
git clone -b master http://git.z2-environment.net/z2-samples.hibernate-basic
25
26
# on Linux / Mac OS:
27
cd z2-base.core/run/bin
28
./gui.sh
29
30
# on Windows:
31
cd z2-base.core\run\bin
32
gui.bat
33
</code></pre>
34
35 10 Henning Blohm
When started, go to http://localhost:8080/hibernate-basic. You should see this:
36
37
!hibernate-basic.png!
38
39 5 Henning Blohm
h2. Details
40
41 7 Henning Blohm
A lot of the things happening here relate to what is explained in [[How to transaction management]].
42 1 Henning Blohm
43 7 Henning Blohm
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.
44
45
The domain module makes use of Hibernate's JPA implementation and integrates with the transaction management provided by *com.zfabrik.jta*.
46
47
Now, step-by-step.
48
49
h3. The domain module and its persistence context
50
51
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.
52
53
In order to integrate with the built-in transaction management the <code>persistence.xml</code> declares the JTA data source 
54
55
<pre><code class="xml">
56
<jta-data-source>components:com.zfabrik.samples.hibernate-basic.domain/DB</jta-data-source>
57
</code></pre>
58
59
and the _Transaction Manager Lookup_ 
60
61
<pre><code class="xml">
62
<property name="hibernate.transaction.manager_lookup_class" value="com.zfabrik.hibernate.TransactionManagerLookup" />
63
</code></pre>
64
65
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. 
66
67
The persistence unit defines only 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 the simplified pattern of exposing persistent objects in the API rather than using Data Transfer Objects (DTOs).
68
69
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.
70
71
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.
72
73
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*:
74
75
<pre><code class="java">
76
public class ThingyRepositoryImpl implements ThingyRepository {
77
	private EntityManagerFactory emf;
78
79
	public ThingyRepositoryImpl() {
80
		// 
81
		// initially create the EMF for this domain
82
		//		
83
		this.emf = ThreadUtil.cleanContextExecute(
84
			this.getClass().getClassLoader(), 
85
			new Callable<EntityManagerFactory>() {
86
				public EntityManagerFactory call() throws Exception {
87
					return Persistence.createEntityManagerFactory("thingies");
88
				};
89
			}
90
		);
91
	}
92
93
	@Override
94
	public void store(Thingy thingy) {
95
		this.em().persist(thingy);
96
	}
97
98
	@SuppressWarnings("unchecked")
99
	@Override
100
	public Collection<Thingy> findAll() {
101
		return this.em().createQuery("select t from Thingy t").getResultList();
102
	}
103
104
	@Override
105
	public void delete(int id) {
106
		Thingy t = this.em().find(Thingy.class, id);
107
		if (t != null) {
108
			this.em().remove(t);
109
		}
110
	}
111
112
	//
113
	// Uses the Entity Manager Util that holds on to EMs created from the passed on EMF
114
	// while the transaction is still open.
115
	//
116
	private EntityManager em() {
117
		return EntityManagerUtil.getEntityManager(
118
			IComponentsLookup.INSTANCE.lookup(
119
				"com.zfabrik.jta/userTransaction", 
120
				TransactionManager.class
121
			),
122
			this.emf
123
		);
124
	}
125
}
126
</code></pre>
127
128
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.
129 8 Henning Blohm
130
h3. The web module, transaction boundaries, and service re-use
131
132 9 Henning Blohm
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":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.web/web/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 would available under the JNDI name "java:comp/env/repos/thingies":
133 8 Henning Blohm
134
<pre><code class="xml">
135
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
136
  <New id="thingyRepository" class="org.eclipse.jetty.plus.jndi.Resource">
137
    <Arg>repos/thingies</Arg>
138
    <Arg>
139
      <New class="javax.naming.LinkRef">
140
        <Arg>components:com.zfabrik.samples.hibernate-basic.domain/repository?type=com.zfabrik.samples.hibernate_basic.thingies.ThingyRepository</Arg>
141
      </New>
142
    </Arg>
143
  </New>
144
</Configure>
145
</code></pre>
146
147
See also "Jetty JNDI":http://docs.codehaus.org/display/JETTY/JNDI.
148
149
Anyway. Now, in the "ControllerFilter":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.web/java/src.impl/com/zfabrik/samples/hibernate_basic/impl/web/ControllerFilter.java we inject the Thingy Repository like this:
150
151
<pre><code class="java">
152
public class ControllerFilter implements Filter {
153
	
154
	// inject thingies repository (see WEB-INF/jetty-env.xml)
155
	@Resource(name="repos/thingies")
156
	private ThingyRepository thingyRepository;
157
	
158
...
159
}
160
</code></pre>
161
162
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
163
164
<pre><code class="java">
165
IComponentsLookup.INSTANCE.lookup("com.zfabrik.samples.hibernate-basic.domain/repository",ThingyRepository.class);
166
</code></pre>
167
168
Finally a word on transaction management. Transaction boundaries are controlled by the "TransactionFilter":http://redmine.z2-environment.net/projects/z2-samples/repository/z2-samples-hibernate-basic/revisions/master/entry/com.zfabrik.samples.hibernate-basic.web/java/src.impl/com/zfabrik/samples/hibernate_basic/impl/web/TransactionFilter.java contained in the sample. We make use of *TransactionUtil* from *com.zabrik.jta* to wrap the actual web app request in a transaction:
169
170
<pre><code class="java">
171
@Override
172
public void doFilter(final ServletRequest sreq, final ServletResponse sres,	final FilterChain chain) throws IOException, ServletException {
173
  HttpServletRequest req = (HttpServletRequest) sreq;
174
  if (req.getDispatcherType()==DispatcherType.REQUEST || req.getDispatcherType()==DispatcherType.ASYNC) {
175
    try {
176
      TransactionUtil.run(
177
        (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction"),
178
        new Callable<Void>() {
179
          public Void call() throws Exception {
180
            chain.doFilter(sreq, sres);
181
            return null;
182
          }
183
        }
184
      );
185
    } catch (Exception e) {
186
      throw new ServletException(e);
187
    }
188
  } else {
189
    chain.doFilter(sreq, sres);
190
  }
191
}
192
</code></pre>