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