2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.api
.service
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Arrays
;
14 import java
.util
.Collection
;
15 import java
.util
.List
;
18 import java
.util
.UUID
;
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
;
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
;
44 public abstract class ServiceBase
<T
extends CdmBase
, DAO
extends ICdmEntityDao
<T
>>
45 implements IService
<T
>, ApplicationContextAware
{
47 @SuppressWarnings("unused")
48 private static final Logger logger
= LogManager
.getLogger();
50 protected ApplicationContext appContext
;
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
58 @Transactional(readOnly
= true)
59 public void lock(T t
, LockOptions lockOptions
) {
60 dao
.lock(t
, lockOptions
);
64 @Transactional(readOnly
= true)
65 public void refresh(T t
, LockOptions lockOptions
, List
<String
> propertyPaths
) {
66 dao
.refresh(t
, lockOptions
, propertyPaths
);
70 @Transactional(readOnly
= false)
76 @Transactional(readOnly
= true)
77 public int count(Class
<?
extends T
> clazz
) {
78 return Long
.valueOf(dao
.count(clazz
)).intValue();
82 @Transactional(readOnly
= false)
83 public DeleteResult
delete(UUID persistentObjectUUID
) {
84 T persistentObject
= dao
.findByUuid(persistentObjectUUID
);
85 return delete(persistentObject
);
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
);
101 @Transactional(readOnly
= false)
102 public DeleteResult
delete(T persistentObject
) {
103 DeleteResult result
= new DeleteResult();
105 dao
.delete(persistentObject
);
106 result
.addDeletedObject(persistentObject
);
107 } catch(DataAccessException e
){
109 result
.addException(e
);
115 @Transactional(readOnly
= true)
116 public boolean exists(UUID uuid
) {
117 return dao
.exists(uuid
);
121 @Transactional(readOnly
= true)
122 public List
<T
> find(Set
<UUID
> uuidSet
) {
123 return dao
.list(uuidSet
, null, null, null, null);
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);
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);
139 @Transactional(readOnly
= true)
140 public List
<T
> loadByIds(List
<Integer
> idList
, List
<String
> propertyPaths
){
141 return dao
.loadList(idList
, null, propertyPaths
);
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
);
151 @Transactional(readOnly
= true)
152 public T
find(UUID uuid
) {
153 return uuid
== null ?
null : dao
.findByUuid(uuid
);
157 @Transactional(readOnly
= true)
158 public T
findWithoutFlush(UUID uuid
) {
159 return uuid
== null ?
null : dao
.findByUuidWithoutFlush(uuid
);
163 @Transactional(readOnly
= true)
164 public T
find(int id
) {
165 return dao
.findById(id
);
169 @Transactional(readOnly
= true)
170 public Session
getSession() {
171 return dao
.getSession();
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
);
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
);
187 @Transactional(readOnly
= true)
188 public T
load(UUID uuid
) {
189 return uuid
== null ?
null : dao
.load(uuid
);
193 @Transactional(readOnly
= true)
194 public T
loadWithUpdate(UUID uuid
) {
199 @Transactional(readOnly
= true)
200 public T
load(int id
, List
<String
> propertyPaths
) {
201 return dao
.load(id
, propertyPaths
);
205 @Transactional(readOnly
= true)
206 public T
loadWithoutInitializing(int id
){
207 return dao
.loadWithoutInitializing(id
);
211 @Transactional(readOnly
= true)
212 public T
load(UUID uuid
, List
<String
> propertyPaths
){
213 return uuid
== null ?
null : dao
.load(uuid
, propertyPaths
);
217 @Transactional(readOnly
= true)
218 public List
<T
> load(List
<UUID
> uuids
, List
<String
> propertyPaths
){
223 List
<T
> entities
= new ArrayList
<>();
224 for(UUID uuid
: uuids
) {
225 entities
.add(uuid
== null ?
null : dao
.load(uuid
, propertyPaths
));
231 @Transactional(readOnly
= false)
232 public T
merge(T newInstance
) {
233 return dao
.merge(newInstance
);
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.
244 public T
merge(T detachedObject
, CdmBase
... removedObjects
) {
245 return dao
.merge(detachedObject
, Arrays
.asList(removedObjects
));
249 @Transactional(readOnly
= false)
250 public MergeResult
<T
> merge(T newInstance
, boolean returnTransientEntity
) {
251 return dao
.merge(newInstance
, returnTransientEntity
);
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
));
261 return mergedObjects
;
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
));
271 return mergedObjects
;
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
);
284 return new DefaultPagerImpl
<>(pageNumber
, numberOfResults
, pageSize
, results
);
288 @Transactional(readOnly
= true)
289 public UUID
refresh(T persistentObject
) {
290 return dao
.refresh(persistentObject
);
294 @Transactional(readOnly
= false)
295 public Map
<UUID
, T
> save(Collection
<?
extends T
> newInstances
) {
296 return dao
.saveAll(newInstances
);
300 @Transactional(readOnly
= false)
301 public <S
extends T
> S
save(S newInstance
) {
302 return dao
.save(newInstance
);
306 @Transactional(readOnly
= false)
307 public UUID
saveOrUpdate(T transientObject
) {
308 return dao
.saveOrUpdate(transientObject
);
312 @Transactional(readOnly
= false)
313 public Map
<UUID
, T
> saveOrUpdate(Collection
<T
> transientInstances
) {
314 return dao
.saveOrUpdateAll(transientInstances
);
318 public void setApplicationContext(ApplicationContext appContext
){
319 this.appContext
= appContext
;
323 protected abstract void setDao(DAO dao
);
326 @Transactional(readOnly
= false)
327 public UUID
update(T transientObject
) {
328 return dao
.update(transientObject
);
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
);
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
){
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
);
347 records
= new ArrayList
<>();
349 return new DefaultPagerImpl
<>(pageIndex
, resultSize
, pageSize
, records
);
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
){
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
);
362 records
= new ArrayList
<>();
364 Pager
<S
> pager
= new DefaultPagerImpl
<>(pageIndex
, resultSize
, pageSize
, records
);
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
){
374 long resultSize
= dao
.count(clazz
, restrictions
);
375 if(AbstractPagerImpl
.hasResultsInRange(resultSize
, pageIndex
, pageSize
)){
377 pageIndex
= pageIndex
== null ?
0 : pageIndex
;
379 if (pageIndex
> 0 && pageSize
!= null) {
380 start
= pageIndex
* pageSize
;
382 records
= dao
.list(clazz
, restrictions
, pageSize
, start
, orderHints
, propertyPaths
);
384 records
= new ArrayList
<>();
386 Pager
<S
> pager
= new DefaultPagerImpl
<>(pageIndex
, resultSize
, pageSize
, records
);
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
398 protected void checkPublished(IPublishable publishable
, boolean includeUnpublished
, String message
) throws UnpublishedException
{
399 if (!(includeUnpublished
|| publishable
.isPublish())){
400 throw new UnpublishedException("Access denied. "+ message
);