cleanup
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / ServiceBase.java
1 /**
2 * Copyright (C) 2007 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
10 package eu.etaxonomy.cdm.api.service;
11
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.UUID;
19
20 import org.apache.logging.log4j.LogManager;
21 import org.apache.logging.log4j.Logger;
22 import org.hibernate.LockOptions;
23 import org.hibernate.Session;
24 import org.hibernate.criterion.Criterion;
25 import org.springframework.context.ApplicationContext;
26 import org.springframework.context.ApplicationContextAware;
27 import org.springframework.dao.DataAccessException;
28 import org.springframework.transaction.annotation.Transactional;
29
30 import eu.etaxonomy.cdm.api.service.pager.Pager;
31 import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
32 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
33 import eu.etaxonomy.cdm.exception.UnpublishedException;
34 import eu.etaxonomy.cdm.model.common.CdmBase;
35 import eu.etaxonomy.cdm.model.common.IPublishable;
36 import eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao;
37 import eu.etaxonomy.cdm.persistence.dao.common.Restriction;
38 import eu.etaxonomy.cdm.persistence.dao.hibernate.common.DaoBase;
39 import eu.etaxonomy.cdm.persistence.dto.MergeResult;
40 import eu.etaxonomy.cdm.persistence.query.Grouping;
41 import eu.etaxonomy.cdm.persistence.query.MatchMode;
42 import eu.etaxonomy.cdm.persistence.query.OrderHint;
43
44 public abstract class ServiceBase<T extends CdmBase, DAO extends ICdmEntityDao<T>>
45 implements IService<T>, ApplicationContextAware {
46
47 @SuppressWarnings("unused")
48 private static final Logger logger = LogManager.getLogger();
49
50 protected ApplicationContext appContext;
51
52 public final static boolean NO_UNPUBLISHED = DaoBase.NO_UNPUBLISHED; //constant for unpublished
53 public final static boolean INCLUDE_UNPUBLISHED = DaoBase.INCLUDE_UNPUBLISHED; //constant for unpublished
54
55 protected DAO dao;
56
57 @Override
58 @Transactional(readOnly = true)
59 public void lock(T t, LockOptions lockOptions) {
60 dao.lock(t, lockOptions);
61 }
62
63 @Override
64 @Transactional(readOnly = true)
65 public void refresh(T t, LockOptions lockOptions, List<String> propertyPaths) {
66 dao.refresh(t, lockOptions, propertyPaths);
67 }
68
69 @Override
70 @Transactional(readOnly = false)
71 public void clear() {
72 dao.clear();
73 }
74
75 @Override
76 @Transactional(readOnly = true)
77 public int count(Class<? extends T> clazz) {
78 return Long.valueOf(dao.count(clazz)).intValue();
79 }
80
81 @Override
82 @Transactional(readOnly = false)
83 public DeleteResult delete(UUID persistentObjectUUID) {
84 T persistentObject = dao.findByUuid(persistentObjectUUID);
85 return delete(persistentObject);
86 }
87
88 @Override
89 @Transactional(readOnly = false)
90 public DeleteResult delete(Collection<UUID> persistentObjectUUIDs) {
91 DeleteResult result = new DeleteResult();
92 for(UUID persistentObjectUUID : persistentObjectUUIDs) {
93 T persistentObject = dao.findByUuid(persistentObjectUUID);
94 DeleteResult dr = delete(persistentObject);
95 result.includeResult(dr);
96 }
97 return result;
98 }
99
100 @Override
101 @Transactional(readOnly = false)
102 public DeleteResult delete(T persistentObject) {
103 DeleteResult result = new DeleteResult();
104 try{
105 dao.delete(persistentObject);
106 result.addDeletedObject(persistentObject);
107 } catch(DataAccessException e){
108 result.setError();
109 result.addException(e);
110 }
111 return result;
112 }
113
114 @Override
115 @Transactional(readOnly = true)
116 public boolean exists(UUID uuid) {
117 return dao.exists(uuid);
118 }
119
120 @Override
121 @Transactional(readOnly = true)
122 public List<T> find(Set<UUID> uuidSet) {
123 return dao.list(uuidSet, null, null, null, null);
124 }
125
126 @Override
127 @Transactional(readOnly = true)
128 public <S extends T> List<S> find(Class<S> clazz, Set<UUID> uuidSet) {
129 return dao.list(clazz, uuidSet, null, null, null, null);
130 }
131
132 @Override
133 @Transactional(readOnly = true)
134 public List<T> findById(Set<Integer> idSet) { //can't be called find(Set<Integer>) as this conflicts with find(Set<UUID)
135 return dao.loadList(idSet, null, null);
136 }
137
138 @Override
139 @Transactional(readOnly = true)
140 public List<T> loadByIds(List<Integer> idList, List<String> propertyPaths){
141 return dao.loadList(idList, null, propertyPaths);
142 }
143
144 @Override
145 @Transactional(readOnly = true)
146 public List<T> loadByIds(List<Integer> idList, List<OrderHint> orderHints, List<String> propertyPaths){
147 return dao.loadList(idList, orderHints, propertyPaths);
148 }
149
150 @Override
151 @Transactional(readOnly = true)
152 public T find(UUID uuid) {
153 return uuid == null ? null : dao.findByUuid(uuid);
154 }
155
156 @Override
157 @Transactional(readOnly = true)
158 public T findWithoutFlush(UUID uuid) {
159 return uuid == null ? null : dao.findByUuidWithoutFlush(uuid);
160 }
161
162 @Override
163 @Transactional(readOnly = true)
164 public T find(int id) {
165 return dao.findById(id);
166 }
167
168 @Override
169 @Transactional(readOnly = true)
170 public Session getSession() {
171 return dao.getSession();
172 }
173
174 @Override
175 @Transactional(readOnly = true)
176 public List<Object[]> group(Class<? extends T> clazz,Integer limit, Integer start, List<Grouping> groups, List<String> propertyPaths) {
177 return dao.group(clazz, limit, start, groups, propertyPaths);
178 }
179
180 @Override
181 @Transactional(readOnly = true)
182 public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths){
183 return dao.list(type, limit, start, orderHints, propertyPaths);
184 }
185
186 @Override
187 @Transactional(readOnly = true)
188 public T load(UUID uuid) {
189 return uuid == null ? null : dao.load(uuid);
190 }
191
192 @Override
193 @Transactional(readOnly = true)
194 public T loadWithUpdate(UUID uuid) {
195 return load(uuid);
196 }
197
198 @Override
199 @Transactional(readOnly = true)
200 public T load(int id, List<String> propertyPaths) {
201 return dao.load(id, propertyPaths);
202 }
203
204 @Override
205 @Transactional(readOnly = true)
206 public T loadWithoutInitializing(int id){
207 return dao.loadWithoutInitializing(id);
208 }
209
210 @Override
211 @Transactional(readOnly = true)
212 public T load(UUID uuid, List<String> propertyPaths){
213 return uuid == null ? null : dao.load(uuid, propertyPaths);
214 }
215
216 @Override
217 @Transactional(readOnly = true)
218 public List<T> load(List<UUID> uuids, List<String> propertyPaths){
219 if(uuids == null) {
220 return null;
221 }
222
223 List<T> entities = new ArrayList<>();
224 for(UUID uuid : uuids) {
225 entities.add(uuid == null ? null : dao.load(uuid, propertyPaths));
226 }
227 return entities;
228 }
229
230 @Override
231 @Transactional(readOnly = false)
232 public T merge(T newInstance) {
233 return dao.merge(newInstance);
234 }
235
236 /**
237 * Same as #merge(T) but with the possibility to fully remove further entities
238 * from the database during the same session. This may become necessary if these
239 * entities were deleted from the detached object graph and are not handled
240 * via Cascade.REMOVE or orphanRemoval, e.g. when children were removed
241 * from its parents and not used elsewhere anymore.
242 */
243 @Override
244 public T merge(T detachedObject, CdmBase... removedObjects) {
245 return dao.merge(detachedObject, Arrays.asList(removedObjects));
246 }
247
248 @Override
249 @Transactional(readOnly = false)
250 public MergeResult<T> merge(T newInstance, boolean returnTransientEntity) {
251 return dao.merge(newInstance, returnTransientEntity);
252 }
253
254 @Override
255 @Transactional(readOnly = false)
256 public List<T> merge(List<T> detachedObjects) {
257 List<T> mergedObjects = new ArrayList<T>();
258 for(T obj : detachedObjects) {
259 mergedObjects.add(dao.merge(obj));
260 }
261 return mergedObjects;
262 }
263
264 @Override
265 @Transactional(readOnly = false)
266 public List<MergeResult<T>> merge(List<T> detachedObjects, boolean returnTransientEntity) {
267 List<MergeResult<T>> mergedObjects = new ArrayList<MergeResult<T>>();
268 for(T obj : detachedObjects) {
269 mergedObjects.add(dao.merge(obj, returnTransientEntity));
270 }
271 return mergedObjects;
272 }
273
274 @Override
275 @Transactional(readOnly = true)
276 public <S extends T> Pager<S> page(Class<S> type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
277 Long numberOfResults = dao.count(type);
278 List<S> results = new ArrayList<>();
279 pageNumber = pageNumber == null ? 0 : pageNumber;
280 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
281 Integer start = pageSize == null ? 0 : pageSize * pageNumber;
282 results = dao.list(type, pageSize, start, orderHints, propertyPaths);
283 }
284 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
285 }
286
287 @Override
288 @Transactional(readOnly = true)
289 public UUID refresh(T persistentObject) {
290 return dao.refresh(persistentObject);
291 }
292
293 @Override
294 @Transactional(readOnly = false)
295 public Map<UUID, T> save(Collection<? extends T> newInstances) {
296 return dao.saveAll(newInstances);
297 }
298
299 @Override
300 @Transactional(readOnly = false)
301 public <S extends T> S save(S newInstance) {
302 return dao.save(newInstance);
303 }
304
305 @Override
306 @Transactional(readOnly = false)
307 public UUID saveOrUpdate(T transientObject) {
308 return dao.saveOrUpdate(transientObject);
309 }
310
311 @Override
312 @Transactional(readOnly = false)
313 public Map<UUID, T> saveOrUpdate(Collection<T> transientInstances) {
314 return dao.saveOrUpdateAll(transientInstances);
315 }
316
317 @Override
318 public void setApplicationContext(ApplicationContext appContext){
319 this.appContext = appContext;
320 }
321
322
323 protected abstract void setDao(DAO dao);
324
325 @Override
326 @Transactional(readOnly = false)
327 public UUID update(T transientObject) {
328 return dao.update(transientObject);
329 }
330
331 @Override
332 @Transactional(readOnly = true)
333 public <S extends T> List<S> list(S example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
334 return dao.list(example, includeProperties, limit, start, orderHints, propertyPaths);
335 }
336
337 @Override
338 @Transactional(readOnly = true)
339 public <S extends T> Pager<S> page(Class<S> clazz, String param, String queryString, MatchMode matchmode,
340 List<Criterion> criteria, Integer pageSize, Integer pageIndex, List<OrderHint> orderHints, List<String> propertyPaths){
341
342 List<S> records;
343 long resultSize = dao.countByParam(clazz, param, queryString, matchmode, criteria);
344 if(AbstractPagerImpl.hasResultsInRange(resultSize, pageIndex, pageSize)){
345 records = dao.findByParam(clazz, param, queryString, matchmode, criteria, pageSize, pageIndex, orderHints, propertyPaths);
346 } else {
347 records = new ArrayList<>();
348 }
349 return new DefaultPagerImpl<>(pageIndex, resultSize, pageSize, records);
350 }
351
352
353 @Override
354 @Transactional(readOnly = true)
355 public <S extends T> Pager<S> pageByParamWithRestrictions(Class<S> clazz, String param, String queryString, MatchMode matchmode, List<Restriction<?>> restrictions, Integer pageSize, Integer pageIndex, List<OrderHint> orderHints, List<String> propertyPaths){
356
357 List<S> records;
358 long resultSize = dao.countByParamWithRestrictions(clazz, param, queryString, matchmode, restrictions);
359 if(AbstractPagerImpl.hasResultsInRange(resultSize, pageIndex, pageSize)){
360 records = dao.findByParamWithRestrictions(clazz, param, queryString, matchmode, restrictions, pageSize, pageIndex, orderHints, propertyPaths);
361 } else {
362 records = new ArrayList<>();
363 }
364 Pager<S> pager = new DefaultPagerImpl<>(pageIndex, resultSize, pageSize, records);
365 return pager;
366 }
367
368 @Override
369 @Transactional(readOnly = true)
370 public <S extends T> Pager<S> page(Class<S> clazz, List<Restriction<?>> restrictions,
371 Integer pageSize, Integer pageIndex, List<OrderHint> orderHints, List<String> propertyPaths){
372
373 List<S> records;
374 long resultSize = dao.count(clazz, restrictions);
375 if(AbstractPagerImpl.hasResultsInRange(resultSize, pageIndex, pageSize)){
376 //#9943
377 pageIndex = pageIndex == null ? 0 : pageIndex;
378 Integer start = 0;
379 if (pageIndex > 0 && pageSize != null) {
380 start = pageIndex * pageSize;
381 }
382 records = dao.list(clazz, restrictions, pageSize, start, orderHints, propertyPaths);
383 } else {
384 records = new ArrayList<>();
385 }
386 Pager<S> pager = new DefaultPagerImpl<>(pageIndex, resultSize, pageSize, records);
387 return pager;
388 }
389
390
391 /**
392 * Throws an exception if the publishable entity should not be published.
393 * @param publishable the publishable entity
394 * @param includeUnpublished should publish be checked
395 * @param message the error message to include
396 * @throws UnpublishedException thrown if entity is not public and unpublished should not be included
397 */
398 protected void checkPublished(IPublishable publishable, boolean includeUnpublished, String message) throws UnpublishedException {
399 if (!(includeUnpublished || publishable.isPublish())){
400 throw new UnpublishedException("Access denied. "+ message);
401 }
402 }
403
404
405
406 }