beb355135c739dc9558e37a565b7b56e9380d263
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / common / VersionableDaoBase.java
1 /**
2 * Copyright (C) 2009 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.persistence.dao.hibernate.common;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Set;
14 import java.util.UUID;
15
16 import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
17 import org.hibernate.criterion.Criterion;
18 import org.hibernate.envers.query.AuditEntity;
19 import org.hibernate.envers.query.AuditQuery;
20 import org.hibernate.envers.query.criteria.AuditCriterion;
21
22 import eu.etaxonomy.cdm.model.common.VersionableEntity;
23 import eu.etaxonomy.cdm.model.view.AuditEvent;
24 import eu.etaxonomy.cdm.model.view.AuditEventRecord;
25 import eu.etaxonomy.cdm.model.view.AuditEventRecordImpl;
26 import eu.etaxonomy.cdm.model.view.context.AuditEventContext;
27 import eu.etaxonomy.cdm.model.view.context.AuditEventContextHolder;
28 import eu.etaxonomy.cdm.persistence.dao.common.AuditEventSort;
29 import eu.etaxonomy.cdm.persistence.dao.common.IVersionableDao;
30 import eu.etaxonomy.cdm.persistence.dao.common.OperationNotSupportedInPriorViewException;
31 import eu.etaxonomy.cdm.persistence.dao.common.Restriction;
32 import eu.etaxonomy.cdm.persistence.query.MatchMode;
33 import eu.etaxonomy.cdm.persistence.query.OrderHint;
34
35 public abstract class VersionableDaoBase<T extends VersionableEntity> extends CdmEntityDaoBase<T> implements IVersionableDao<T> {
36 private static final Logger logger = LogManager.getLogger(VersionableDaoBase.class);
37
38 public VersionableDaoBase(Class<T> type) {
39 super(type);
40 }
41
42 protected AuditEvent getAuditEventFromContext() {
43 AuditEventContext auditEventContext = AuditEventContextHolder.getContext();
44
45 AuditEvent auditEvent = auditEventContext.getAuditEvent();
46 if(auditEvent != null) {
47 logger.debug(" AuditEvent found, returning " + auditEvent);
48 return auditEvent;
49 } else {
50 logger.debug(" AuditEvent is NULL, returning AuditEvent.CURRENT_VIEW");
51 return AuditEvent.CURRENT_VIEW;
52 }
53 }
54
55 protected void checkNotInPriorView(String message) {
56 AuditEvent auditEvent = getAuditEventFromContext();
57 if(!auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
58 throw new OperationNotSupportedInPriorViewException(message);
59 }
60 }
61
62 @Override
63 public T findByUuid(UUID uuid) {
64 AuditEvent auditEvent = getAuditEventFromContext();
65 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
66 return super.findByUuid(uuid);
67 } else {
68 AuditQuery query = makeAuditQuery(null, auditEvent);
69 query.add(AuditEntity.property("uuid").eq(uuid));
70 @SuppressWarnings("unchecked")
71 T result = (T)query.getSingleResult();
72 return result;
73 }
74 }
75
76 @Override
77 public <S extends T> List<S> findByParam(Class<S> clazz, String param, String queryString, MatchMode matchmode, List<Criterion> criterion, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
78 checkNotInPriorView("IdentifiableDaoBase.findByParam(Class<? extends T> clazz, String queryString, MatchMode matchmode, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths)");
79 return super.findByParam(clazz, param, queryString, matchmode, criterion, pageSize, pageNumber, orderHints, propertyPaths);
80 }
81
82 @Override
83 public <S extends T> List<S> findByParamWithRestrictions(Class<S> clazz, String param, String queryString, MatchMode matchmode, List<Restriction<?>> restrictions, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
84 checkNotInPriorView("IdentifiableDaoBase.findByParam(Class<? extends T> clazz, String queryString, MatchMode matchmode, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths)");
85 return super.findByParamWithRestrictions(clazz, param, queryString, matchmode, restrictions, pageSize, pageNumber, orderHints, propertyPaths);
86 }
87
88 @Override
89 public T load(UUID uuid) {
90 AuditEvent auditEvent = getAuditEventFromContext();
91 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
92 return super.load(uuid);
93 } else {
94 AuditQuery query = makeAuditQuery(null, auditEvent);
95 query.add(AuditEntity.property("uuid").eq(uuid));
96 @SuppressWarnings("unchecked")
97 T t = (T)query.getSingleResult();
98 defaultBeanInitializer.load(t);
99 return t;
100 }
101 }
102
103 @Override
104 public T load(UUID uuid, List<String> propertyPaths) {
105 return this.load(uuid, INCLUDE_UNPUBLISHED, propertyPaths);
106 }
107
108 @Override
109 protected T load(UUID uuid, boolean includeUnpublished, List<String> propertyPaths) {
110 AuditEvent auditEvent = getAuditEventFromContext();
111 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
112 return super.load(uuid, includeUnpublished, propertyPaths);
113 } else {
114 //TODO includeUnpublished
115 AuditQuery query = makeAuditQuery(null, auditEvent);
116 query.add(AuditEntity.property("uuid").eq(uuid));
117 @SuppressWarnings("unchecked")
118 T t = (T)query.getSingleResult();
119 defaultBeanInitializer.initialize(t, propertyPaths);
120 return t;
121 }
122 }
123
124
125 @Override
126 public Boolean exists(UUID uuid) {
127 AuditEvent auditEvent = getAuditEventFromContext();
128 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
129 return super.exists(uuid);
130 } else {
131 AuditQuery query = makeAuditQuery(null, auditEvent);
132 query.add(AuditEntity.property("uuid").eq(uuid));
133 return null != query.getSingleResult();
134 }
135 }
136
137 @Override
138 public long count() {
139 AuditEvent auditEvent = getAuditEventFromContext();
140 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
141 return super.count();
142 } else {
143 return this.count(null);
144 }
145 }
146
147 @Override
148 public long count(Class<? extends T> clazz) {
149 AuditEvent auditEvent = getAuditEventFromContext();
150 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
151 return super.count(clazz);
152 } else {
153 AuditQuery query = makeAuditQuery(clazz, auditEvent);
154
155 query.addProjection(AuditEntity.id().count());
156
157 return (Long)query.getSingleResult();
158 }
159 }
160
161 @Override
162 public List<T> list(Integer limit, Integer start) {
163 AuditEvent auditEvent = getAuditEventFromContext();
164 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
165 return super.list(limit, start);
166 } else {
167 return this.list(null, limit, start);
168 }
169 }
170
171 @Override
172 public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start) {
173 AuditEvent auditEvent = getAuditEventFromContext();
174 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
175 return super.list(type,limit, start);
176 } else {
177 return this.list(type, limit, start, null,null);
178 }
179 }
180
181 @Override
182 public <S extends T> List<S> list(Class<S> clazz, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
183 AuditEvent auditEvent = getAuditEventFromContext();
184 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
185 return super.list(clazz, limit, start, orderHints, propertyPaths);
186 } else {
187 AuditQuery query = makeAuditQuery(clazz, auditEvent);
188
189 addOrder(query,orderHints);
190 addLimitAndStart(query, limit, start);
191
192 @SuppressWarnings("unchecked")
193 List<S> result = query.getResultList();
194 defaultBeanInitializer.initializeAll(result, propertyPaths);
195 return result;
196 }
197 }
198
199 protected void addOrder(AuditQuery query, List<OrderHint> orderHints) {
200 if(orderHints != null && !orderHints.isEmpty()) {
201 for(OrderHint orderHint : orderHints) {
202 orderHint.add(query);
203 }
204 }
205 }
206
207 @Override
208 public List<AuditEventRecord<T>> getAuditEvents(T t, Integer pageSize, Integer pageNumber, AuditEventSort sort, List<String> propertyPaths) {
209 AuditEvent auditEvent = getAuditEventFromContext();
210
211 AuditQuery query = getAuditReader().createQuery().forRevisionsOfEntity(type, false, true);
212 query.add(AuditEntity.id().eq(t.getId()));
213 if(sort == null) {
214 sort = AuditEventSort.BACKWARDS;
215 }
216
217 if(sort.equals(AuditEventSort.BACKWARDS)) {
218 if(!auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
219 query.add(AuditEntity.revisionNumber().lt(auditEvent.getRevisionNumber()));
220 }
221 query.addOrder(AuditEntity.revisionNumber().desc());
222 } else {
223 if(!auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
224 query.add(AuditEntity.revisionNumber().gt(auditEvent.getRevisionNumber()));
225 }
226 query.addOrder(AuditEntity.revisionNumber().asc());
227 }
228
229 if(pageSize != null) {
230 query.setMaxResults(pageSize);
231 if(pageNumber != null) {
232 query.setFirstResult(pageNumber * pageSize);
233 } else {
234 query.setFirstResult(0);
235 }
236 }
237
238 /**
239 * At the moment we need to transform the data manually
240 */
241 @SuppressWarnings("unchecked")
242 List<Object[]> objs = query.getResultList();
243 List<AuditEventRecord<T>> records = new ArrayList<AuditEventRecord<T>>();
244
245 for(Object[] obj : objs) {
246 records.add(new AuditEventRecordImpl<T>(obj));
247 }
248
249 for(AuditEventRecord<T> record : records) {
250 defaultBeanInitializer.initialize(record.getAuditableObject(), propertyPaths);
251 }
252 return records;
253 }
254
255 @Override
256 public long countAuditEvents(T t, AuditEventSort sort) {
257 AuditEvent auditEvent = getAuditEventFromContext();
258
259 AuditQuery query = getAuditReader().createQuery().forRevisionsOfEntity(type, false, true);
260 query.add(AuditEntity.id().eq(t.getId()));
261
262 if(!auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
263 if(sort == null) {
264 sort = AuditEventSort.BACKWARDS;
265 }
266
267 if(sort.equals(AuditEventSort.BACKWARDS)) {
268 query.add(AuditEntity.revisionNumber().lt(auditEvent.getRevisionNumber()));
269 } else {
270 query.add(AuditEntity.revisionNumber().gt(auditEvent.getRevisionNumber()));
271 }
272 }
273
274 query.addProjection(AuditEntity.revisionNumber().count());
275
276 return (Long)query.getSingleResult();
277 }
278
279 @Override
280 public AuditEventRecord<T> getNextAuditEvent(T t) {
281 List<AuditEventRecord<T>> auditEvents = getAuditEvents(t,1,0,AuditEventSort.FORWARDS, null);
282 if(auditEvents.isEmpty()) {
283 return null;
284 } else {
285 return auditEvents.get(0);
286 }
287 }
288
289 @Override
290 public AuditEventRecord<T> getPreviousAuditEvent(T t) {
291 List<AuditEventRecord<T>> auditEvents = getAuditEvents(t,1,0,AuditEventSort.BACKWARDS, null);
292 if(auditEvents.isEmpty()) {
293 return null;
294 } else {
295 return auditEvents.get(0);
296 }
297 }
298
299 @Override
300 public long countAuditEvents(Class<? extends T> clazz, AuditEvent from, AuditEvent to, List<AuditCriterion> criteria) {
301 AuditQuery query = null;
302
303 if(clazz == null) {
304 query = getAuditReader().createQuery().forRevisionsOfEntity(type, false, true);
305 } else {
306 query = getAuditReader().createQuery().forRevisionsOfEntity(clazz, false, true);
307 }
308
309 if(from != null) {
310 query.add(AuditEntity.revisionNumber().ge(from.getRevisionNumber()));
311 }
312
313 if(to != null && !to.equals(AuditEvent.CURRENT_VIEW)) {
314 query.add(AuditEntity.revisionNumber().lt(to.getRevisionNumber()));
315 }
316
317 addCriteria(query,criteria);
318
319 query.addProjection(AuditEntity.revisionNumber().count());
320
321 return (Long)query.getSingleResult();
322 }
323
324 protected void addCriteria(AuditQuery query, List<AuditCriterion> criteria) {
325 if(criteria != null) {
326 for(AuditCriterion c : criteria) {
327 query.add(c);
328 }
329 }
330 }
331
332 @Override
333 public List<AuditEventRecord<T>> getAuditEvents(Class<? extends T> clazz,AuditEvent from, AuditEvent to, List<AuditCriterion> criteria, Integer pageSize, Integer pageNumber, AuditEventSort sort, List<String> propertyPaths) {
334 AuditQuery query = null;
335
336 if(clazz == null) {
337 query = getAuditReader().createQuery().forRevisionsOfEntity(type, false, true);
338 } else {
339 query = getAuditReader().createQuery().forRevisionsOfEntity(clazz, false, true);
340 }
341
342 if(from != null) {
343 query.add(AuditEntity.revisionNumber().ge(from.getRevisionNumber()));
344 }
345
346 if(to != null && !to.equals(AuditEvent.CURRENT_VIEW)) {
347 query.add(AuditEntity.revisionNumber().lt(to.getRevisionNumber()));
348 }
349
350 if(sort.equals(AuditEventSort.BACKWARDS)) {
351 query.addOrder(AuditEntity.revisionNumber().desc());
352 } else {
353 query.addOrder(AuditEntity.revisionNumber().asc());
354 }
355
356 addCriteria(query,criteria);
357
358 if(pageSize != null) {
359 query.setMaxResults(pageSize);
360 if(pageNumber != null) {
361 query.setFirstResult(pageNumber * pageSize);
362 } else {
363 query.setFirstResult(0);
364 }
365 }
366
367 /**
368 * At the moment we need to transform the data manually
369 */
370 @SuppressWarnings("unchecked")
371 List<Object[]> objs = query.getResultList();
372 List<AuditEventRecord<T>> records = new ArrayList<>();
373
374 for(Object[] obj : objs) {
375 records.add(new AuditEventRecordImpl<>(obj));
376 }
377
378 for(AuditEventRecord<T> record : records) {
379 defaultBeanInitializer.initialize(record.getAuditableObject(), propertyPaths);
380 }
381 return records;
382 }
383
384 @Override
385 public long countByParam(Class<? extends T> clazz, String param, String queryString, MatchMode matchmode, List<Criterion> criterion) {
386 checkNotInPriorView("IdentifiableDaoBase.findByParam(Class<? extends T> clazz, String queryString, MatchMode matchmode, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths)");
387 return super.countByParam(clazz, param, queryString, matchmode, criterion);
388 }
389
390 @Override
391 public long count(T example, Set<String> includeProperties) {
392 this.checkNotInPriorView("count(T example, Set<String> includeProperties)");
393 return super.count(example, includeProperties);
394 }
395
396 @Override
397 public <S extends T> List<S> list(S example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
398 this.checkNotInPriorView("list(S example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {");
399 return super.list(example, includeProperties, limit, start, orderHints, propertyPaths);
400 }
401 }