1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package ch.elca.el4j.services.persistence.jpa.dao;
19
20 import java.io.Serializable;
21 import java.lang.reflect.ParameterizedType;
22 import java.util.Collection;
23 import java.util.List;
24
25 import javax.persistence.EntityManager;
26 import javax.persistence.PersistenceException;
27 import javax.persistence.PersistenceUnitUtil;
28 import javax.persistence.criteria.CriteriaQuery;
29
30 import org.apache.commons.collections.map.ReferenceMap;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.springframework.beans.factory.InitializingBean;
34 import org.springframework.dao.DataAccessException;
35 import org.springframework.dao.DataIntegrityViolationException;
36 import org.springframework.dao.DataRetrievalFailureException;
37 import org.springframework.dao.OptimisticLockingFailureException;
38 import org.springframework.orm.jpa.JpaCallback;
39 import org.springframework.transaction.annotation.Propagation;
40 import org.springframework.transaction.annotation.Transactional;
41
42 import ch.elca.el4j.services.persistence.generic.dao.annotations.ReturnsUnchangedParameter;
43 import ch.elca.el4j.services.persistence.hibernate.dao.extent.DataExtent;
44 import ch.elca.el4j.services.persistence.hibernate.dao.extent.ExtentEntity;
45 import ch.elca.el4j.services.persistence.jpa.criteria.QueryBuilder;
46 import ch.elca.el4j.services.persistence.jpa.dao.extentstrategies.ExtentFetcher;
47 import ch.elca.el4j.util.codingsupport.Reject;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public class GenericJpaDao<T, ID extends Serializable>
63 extends ConvenienceJpaDaoSupport
64 implements ConvenienceGenericJpaDao<T, ID>, InitializingBean {
65
66
67
68
69 private static Logger s_logger = LoggerFactory.getLogger(GenericJpaDao.class);
70
71
72
73
74 private Class<T> persistentClass;
75
76
77
78
79
80 private ExtentFetcher extentFetcher;
81
82
83
84
85 @SuppressWarnings("unchecked")
86 public GenericJpaDao() {
87 try {
88 this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
89 .getGenericSuperclass()).getActualTypeArguments()[0];
90
91 } catch (Exception e) {
92
93
94
95 }
96 }
97
98
99
100
101
102
103
104
105 public void setPersistentClass(Class<T> c) {
106 Reject.ifNull(c);
107 persistentClass = c;
108 }
109
110
111
112
113 public Class<T> getPersistentClass() {
114 assert persistentClass != null;
115 return persistentClass;
116 }
117
118
119
120
121 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
122 public T findById(ID id)
123 throws DataAccessException, DataRetrievalFailureException {
124 return (T) getConvenienceJpaTemplate().findByIdStrong(
125 getPersistentClass(), id, getPersistentClassName());
126 }
127
128
129
130
131 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
132 public T findByIdLazy(ID id)
133 throws DataAccessException, DataRetrievalFailureException {
134 return (T) getConvenienceJpaTemplate().findByIdStrongLazy(
135 getPersistentClass(), id, getPersistentClassName());
136 }
137
138
139
140
141 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
142 public List<T> getAll() throws DataAccessException {
143 return getConvenienceJpaTemplate().findByCriteria(getOrderedCriteria());
144 }
145
146
147 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
148 public List<T> findByQuery(final QueryBuilder criteria)
149 throws DataAccessException {
150
151 ConvenienceJpaTemplate template = getConvenienceJpaTemplate();
152
153 return template.execute(new JpaCallback<List<T>>() {
154
155 @Override
156 public List<T> doInJpa(EntityManager em) throws PersistenceException {
157 return criteria.applySelect(em).getResultList(persistentClass);
158 }
159
160 });
161 }
162
163
164 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
165 public List<T> findByQuery(final QueryBuilder criteria, final int firstResult, final int maxResults)
166 throws DataAccessException {
167
168 ConvenienceJpaTemplate template = getConvenienceJpaTemplate();
169
170 return template.execute(new JpaCallback<List<T>>() {
171
172 @Override
173 public List<T> doInJpa(EntityManager em) throws PersistenceException {
174 return criteria.applySelect(em).getResultList(persistentClass, firstResult, maxResults);
175 }
176
177 });
178 }
179
180
181 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
182 public int findCountByQuery(final QueryBuilder criteria)
183 throws DataAccessException {
184
185 ConvenienceJpaTemplate template = getConvenienceJpaTemplate();
186
187 return template.execute(new JpaCallback<Integer>() {
188
189 @Override
190 public Integer doInJpa(EntityManager em) throws PersistenceException {
191 return criteria.applyCount(em).getCount();
192 }
193
194 });
195 }
196
197
198 @SuppressWarnings("unchecked")
199 @ReturnsUnchangedParameter
200 @Transactional(propagation = Propagation.REQUIRED)
201 public T merge(T entity) throws DataAccessException,
202 DataIntegrityViolationException, OptimisticLockingFailureException {
203
204 return (T) getConvenienceJpaTemplate().mergeStrong(entity, getPersistentClassName());
205 }
206
207
208
209
210 @ReturnsUnchangedParameter
211 @Transactional(propagation = Propagation.REQUIRED)
212 public T persist(T entity) throws DataAccessException,
213 DataIntegrityViolationException, OptimisticLockingFailureException {
214
215 getConvenienceJpaTemplate().persist(entity);
216 return entity;
217 }
218
219
220
221
222
223
224
225
226
227
228
229 @Deprecated
230 public T saveOrUpdate(T entity) {
231 return merge(entity);
232 }
233
234
235 @Deprecated
236 @ReturnsUnchangedParameter
237 @Transactional(propagation = Propagation.REQUIRED)
238 public T saveOrUpdateAndFlush(T entity) throws DataAccessException,
239 DataIntegrityViolationException, OptimisticLockingFailureException {
240
241 T tmp = saveOrUpdate(entity);
242 flush();
243 return tmp;
244 }
245
246
247 @Transactional(propagation = Propagation.REQUIRED)
248 public void delete(T entity) throws DataAccessException {
249 T e = entity;
250 getConvenienceJpaTemplate().remove(e);
251 }
252
253
254 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
255 public T refresh(T entity) throws DataAccessException,
256 DataRetrievalFailureException {
257 T e = entity;
258 getConvenienceJpaTemplate().refresh(e);
259 return e;
260 }
261
262
263 @Deprecated
264 @Transactional(propagation = Propagation.REQUIRED)
265 public void delete(ID id) throws DataAccessException {
266 getConvenienceJpaTemplate().removeStrong(getPersistentClass(),
267 id, getPersistentClassName());
268 }
269
270
271 @Transactional(propagation = Propagation.REQUIRED)
272 public void deleteById(ID id) throws DataAccessException {
273 getConvenienceJpaTemplate().removeStrong(getPersistentClass(),
274 id, getPersistentClassName());
275 }
276
277
278 @Transactional(propagation = Propagation.REQUIRED)
279 public void delete(Collection<T> entities) throws DataAccessException,
280 DataIntegrityViolationException, OptimisticLockingFailureException {
281 getConvenienceJpaTemplate().removeAll(entities);
282 }
283
284
285 @Transactional(propagation = Propagation.REQUIRED)
286 public void deleteAll()
287 throws OptimisticLockingFailureException, DataAccessException {
288 List<T> list = getAll();
289 if (list.size() > 0) {
290 delete(list);
291 }
292 }
293
294
295 @Transactional(propagation = Propagation.REQUIRED)
296 public void flush() {
297 getConvenienceJpaTemplate().flush();
298 }
299
300
301 public CriteriaQuery<T> getOrderedCriteria() {
302 CriteriaQuery<T> criteria
303 = getJpaTemplate().execute(new JpaCallback<CriteriaQuery<T>>() {
304
305 @Override
306 public CriteriaQuery<T> doInJpa(EntityManager em) throws PersistenceException {
307 CriteriaQuery<T> criteria = em.getCriteriaBuilder().createQuery(persistentClass);
308 criteria.from(persistentClass);
309 return criteria;
310 }
311 });
312
313 return makeDistinct(criteria);
314 }
315
316
317
318
319
320
321
322
323 protected String getPersistentClassName() {
324 return getPersistentClass().getSimpleName();
325 }
326
327
328
329
330
331 protected CriteriaQuery<T> makeDistinct(CriteriaQuery<T> criteria) {
332 return criteria.distinct(true);
333 }
334
335
336
337
338 @SuppressWarnings("unchecked")
339 @Override
340 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
341 public T reload(T entity) throws DataAccessException, DataRetrievalFailureException {
342 PersistenceUnitUtil util = getConvenienceJpaTemplate().getEntityManagerFactory().getPersistenceUnitUtil();
343 return findById((ID) util.getIdentifier(entity));
344 }
345
346
347
348
349
350
351 public ExtentFetcher getExtentFetcher() {
352 return extentFetcher;
353 }
354
355
356
357
358 public void setExtentFetcher(ExtentFetcher extentFetcher) {
359 this.extentFetcher = extentFetcher;
360 }
361
362
363
364
365
366
367
368
369
370
371
372
373 protected List<T> fetchExtent(List<T> objects, DataExtent extent)
374 throws DataAccessException {
375
376 if (extent != null) {
377 ReferenceMap fetchedObjects = new ReferenceMap();
378 for (Object obj : objects) {
379 fetchExtentObject(obj, extent.getRootEntity(), fetchedObjects);
380 }
381 }
382 return objects;
383 }
384
385
386
387
388
389
390
391
392
393
394
395
396 protected T fetchExtent(T object, DataExtent extent)
397 throws DataAccessException {
398
399 if (extent != null) {
400 ReferenceMap fetchedObjects = new ReferenceMap();
401 fetchExtentObject(object, extent.getRootEntity(), fetchedObjects);
402 }
403 return object;
404 }
405
406
407
408
409
410
411
412
413
414
415
416 private void fetchExtentObject(Object object, ExtentEntity entity, ReferenceMap fetchedObjects)
417 throws DataAccessException {
418 s_logger.debug("using extent-fetcher " + extentFetcher.getClass());
419 extentFetcher.fetchExtentObject(object, entity, fetchedObjects);
420 }
421
422
423 @Override
424 public List<T> findByQuery(QueryBuilder criteria, DataExtent extent) throws DataAccessException {
425 return fetchExtent(findByQuery(criteria), extent);
426 }
427
428
429 @Override
430 public List<T> findByQuery(QueryBuilder criteria, int firstResult, int maxResults, DataExtent extent)
431 throws DataAccessException {
432 return fetchExtent(findByQuery(criteria, firstResult, maxResults), extent);
433 }
434
435
436 @Override
437 public T findById(ID id, DataExtent extent) throws DataRetrievalFailureException, DataAccessException {
438 return fetchExtent((T) getConvenienceJpaTemplate().findByIdStrong(
439 getPersistentClass(), id, getPersistentClassName()), extent);
440 }
441
442
443 @Override
444 public List<T> getAll(DataExtent extent) throws DataAccessException {
445 return fetchExtent(getConvenienceJpaTemplate().findByCriteria(getOrderedCriteria()), extent);
446 }
447
448
449 @Override
450 public T refresh(T entity, DataExtent extent) throws DataAccessException, DataRetrievalFailureException {
451 getConvenienceJpaTemplate().refresh(entity);
452 return fetchExtent(entity, extent);
453 }
454
455
456 @Override
457 public T reload(T entity, DataExtent extent) throws DataAccessException, DataRetrievalFailureException {
458 return fetchExtent(reload(entity), extent);
459 }
460
461 }