Project

General

Profile

Sample-hibernate-basic » History » Version 14

Henning Blohm, 03.05.2014 19:48

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 14 Henning Blohm
This sample makes use of the [[Hibernate Addon]] and is most likely the best documentation on how to use its supporting functionality.
8
9 5 Henning Blohm
h2. Prerequisites
10
11 11 Henning Blohm
You need to run Java DB as network server on localhost. This is explained next.
12 1 Henning Blohm
13 11 Henning Blohm
The application will create a database "z2-samples"
14 5 Henning Blohm
15 11 Henning Blohm
{{include(How to run Java db)}}
16
17
18
h2. Run the sample
19 5 Henning Blohm
20 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:
21 5 Henning Blohm
22
<pre><code class="ruby">
23
mkdir install
24
cd install 
25
git clone -b master http://git.z2-environment.net/z2-base.core
26
git clone -b master http://git.z2-environment.net/z2-samples.hibernate-basic
27
28
# on Linux / Mac OS:
29
cd z2-base.core/run/bin
30
./gui.sh
31
32
# on Windows:
33
cd z2-base.core\run\bin
34
gui.bat
35
</code></pre>
36
37 10 Henning Blohm
When started, go to http://localhost:8080/hibernate-basic. You should see this:
38
39
!hibernate-basic.png!
40
41 5 Henning Blohm
h2. Details
42
43 7 Henning Blohm
A lot of the things happening here relate to what is explained in [[How to transaction management]].
44 1 Henning Blohm
45 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.
46
47
The domain module makes use of Hibernate's JPA implementation and integrates with the transaction management provided by *com.zfabrik.jta*.
48
49
Now, step-by-step.
50
51
h3. The domain module and its persistence context
52
53
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.
54
55
In order to integrate with the built-in transaction management the <code>persistence.xml</code> declares the JTA data source 
56
57
<pre><code class="xml">
58
<jta-data-source>components:com.zfabrik.samples.hibernate-basic.domain/DB</jta-data-source>
59
</code></pre>
60 1 Henning Blohm
61 14 Henning Blohm
and the _JTA Platform_ (Hibernate's transaction management abstraction since v4.3) 
62 1 Henning Blohm
63 7 Henning Blohm
<pre><code class="xml">
64 14 Henning Blohm
<property name="hibernate.transaction.jta.platform" value="com.zfabrik.hibernate.Z2JtaPlatform"/>
65 7 Henning Blohm
</code></pre>
66
67 14 Henning Blohm
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 that comes built-in with Z2 (other samples, such as [[Sample-jta-plain]], [[Sample-springds-hibernate]] show alternative approaches).
68 7 Henning Blohm
69
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).
70
71 12 Udo Offermann
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 to retrieve, store, and delete thingies.
72 7 Henning Blohm
73
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.
74
75
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*:
76
77
<pre><code class="java">
78 1 Henning Blohm
public class ThingyRepositoryImpl implements ThingyRepository {
79
	private EntityManagerFactory emf;
80
81 14 Henning Blohm
	/**
82
	 * Create the repo
83
	 */ 
84 1 Henning Blohm
	public ThingyRepositoryImpl() {
85 14 Henning Blohm
		/*
86
		 * We switch the context class loader so that Hibernate finds our persistence.xml.
87
		 * We use the EntityManagerUtil so that Hibernate doesn't freak out in a 
88
		 * no-Initial-Context-Factory (but URL for lookup) naming environment.
89
		 */
90 7 Henning Blohm
		this.emf = ThreadUtil.cleanContextExecute(
91 14 Henning Blohm
			this.getClass().getClassLoader(),
92 7 Henning Blohm
			new Callable<EntityManagerFactory>() {
93 14 Henning Blohm
				@Override
94 7 Henning Blohm
				public EntityManagerFactory call() throws Exception {
95 14 Henning Blohm
					return EntityManagerUtil.createEntityManagerFactory("thingies");
96
				}
97 7 Henning Blohm
			}
98
		);
99
	}
100
101
	@Override
102
	public void store(Thingy thingy) {
103
		this.em().persist(thingy);
104
	}
105
106
	@SuppressWarnings("unchecked")
107
	@Override
108
	public Collection<Thingy> findAll() {
109
		return this.em().createQuery("select t from Thingy t").getResultList();
110
	}
111
112
	@Override
113
	public void delete(int id) {
114
		Thingy t = this.em().find(Thingy.class, id);
115
		if (t != null) {
116
			this.em().remove(t);
117
		}
118
	}
119
120
	//
121
	// Uses the Entity Manager Util that holds on to EMs created from the passed on EMF
122
	// while the transaction is still open.
123
	//
124
	private EntityManager em() {
125
		return EntityManagerUtil.getEntityManager(
126 1 Henning Blohm
			IComponentsLookup.INSTANCE.lookup(
127 7 Henning Blohm
				"com.zfabrik.jta/userTransaction", 
128
				TransactionManager.class
129
			),
130
			this.emf
131
		);
132
	}
133
}
134 8 Henning Blohm
</code></pre>
135
136 14 Henning Blohm
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":http://www.z2-environment.net/blog/2012/07/for-techies-protecting-java-in-a-modular-world-context-classloaders/).
137 13 Udo Offermann
138 8 Henning Blohm
h3. The web module, transaction boundaries, and service re-use
139
140
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 is available under the JNDI name "java:comp/env/repos/thingies":
141
142
<pre><code class="xml">
143
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
144
  <New id="thingyRepository" class="org.eclipse.jetty.plus.jndi.Resource">
145
    <Arg>repos/thingies</Arg>
146
    <Arg>
147
      <New class="javax.naming.LinkRef">
148
        <Arg>components:com.zfabrik.samples.hibernate-basic.domain/repository?type=com.zfabrik.samples.hibernate_basic.thingies.ThingyRepository</Arg>
149
      </New>
150
    </Arg>
151
  </New>
152
</Configure>
153
</code></pre>
154
155
See also "Jetty JNDI":http://docs.codehaus.org/display/JETTY/JNDI.
156
157
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:
158
159
<pre><code class="java">
160
public class ControllerFilter implements Filter {
161
	
162
	// inject thingies repository (see WEB-INF/jetty-env.xml)
163
	@Resource(name="repos/thingies")
164
	private ThingyRepository thingyRepository;
165
	
166
...
167
}
168
</code></pre>
169
170
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
171
172
<pre><code class="java">
173
IComponentsLookup.INSTANCE.lookup("com.zfabrik.samples.hibernate-basic.domain/repository",ThingyRepository.class);
174
</code></pre>
175
176
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:
177
178
<pre><code class="java">
179
@Override
180
public void doFilter(final ServletRequest sreq, final ServletResponse sres,	final FilterChain chain) throws IOException, ServletException {
181
  HttpServletRequest req = (HttpServletRequest) sreq;
182
  if (req.getDispatcherType()==DispatcherType.REQUEST || req.getDispatcherType()==DispatcherType.ASYNC) {
183
    try {
184
      TransactionUtil.run(
185
        (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction"),
186
        new Callable<Void>() {
187
          public Void call() throws Exception {
188
            chain.doFilter(sreq, sres);
189
            return null;
190
          }
191
        }
192
      );
193
    } catch (Exception e) {
194
      throw new ServletException(e);
195
    }
196
  } else {
197
    chain.doFilter(sreq, sres);
198 1 Henning Blohm
  }
199
}
200
</code></pre>