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
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collection
;
15 import java
.util
.Enumeration
;
16 import java
.util
.HashSet
;
17 import java
.util
.Iterator
;
18 import java
.util
.List
;
19 import java
.util
.Locale
;
22 import java
.util
.UUID
;
24 import org
.apache
.commons
.lang
.StringUtils
;
25 import org
.apache
.log4j
.Logger
;
26 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
27 import org
.springframework
.beans
.factory
.annotation
.Qualifier
;
28 import org
.springframework
.stereotype
.Service
;
29 import org
.springframework
.transaction
.annotation
.Transactional
;
31 import eu
.etaxonomy
.cdm
.api
.service
.UpdateResult
.Status
;
32 import eu
.etaxonomy
.cdm
.api
.service
.config
.DeleteConfiguratorBase
;
33 import eu
.etaxonomy
.cdm
.api
.service
.config
.TermDeletionConfigurator
;
34 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
35 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
36 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
37 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
38 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
39 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
40 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
41 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
42 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
43 import eu
.etaxonomy
.cdm
.model
.common
.LanguageStringBase
;
44 import eu
.etaxonomy
.cdm
.model
.common
.Representation
;
45 import eu
.etaxonomy
.cdm
.model
.common
.TermBase
;
46 import eu
.etaxonomy
.cdm
.model
.common
.TermType
;
47 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
48 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
49 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
50 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaType
;
51 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
52 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IDefinedTermDao
;
53 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ILanguageStringBaseDao
;
54 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ILanguageStringDao
;
55 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IRepresentationDao
;
56 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
57 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
58 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
61 @Transactional(readOnly
= true)
62 public class TermServiceImpl
extends IdentifiableServiceBase
<DefinedTermBase
,IDefinedTermDao
> implements ITermService
{
63 @SuppressWarnings("unused")
64 private static final Logger logger
= Logger
.getLogger(TermServiceImpl
.class);
66 private ILanguageStringDao languageStringDao
;
69 @Qualifier("langStrBaseDao")
70 private ILanguageStringBaseDao languageStringBaseDao
;
71 private IRepresentationDao representationDao
;
74 public void setLanguageStringDao(ILanguageStringDao languageStringDao
) {
75 this.languageStringDao
= languageStringDao
;
79 public void setRepresentationDao(IRepresentationDao representationDao
) {
80 this.representationDao
= representationDao
;
85 protected void setDao(IDefinedTermDao dao
) {
90 public <T
extends DefinedTermBase
> List
<T
> listByTermType(TermType termType
, Integer limit
, Integer start
,
91 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
92 return dao
.listByTermType(termType
, limit
, start
, orderHints
, propertyPaths
);
96 public DefinedTermBase
getByUri(URI uri
) {
97 return dao
.findByUri(uri
);
101 public Language
getLanguageByIso(String iso639
) {
102 return dao
.getLanguageByIso(iso639
);
106 public Language
getLanguageByLabel(String label
) {
107 return Language
.getLanguageByLabel(label
);
111 public List
<Language
> getLanguagesByLocale(Enumeration
<Locale
> locales
){
112 return dao
.getLanguagesByLocale(locales
);
116 public <TERM
extends DefinedTermBase
> TERM
findByIdInVocabulary(String id
, UUID vocabularyUuid
, Class
<TERM
> clazz
) throws IllegalArgumentException
{
117 List
<TERM
> list
= dao
.getDefinedTermByIdInVocabulary(id
, vocabularyUuid
, clazz
, null, null);
120 }else if (list
.size() == 1){
123 String message
= "There is more then 1 (%d) term with the same id in vocabulary. This is forbidden. Check the state of your database.";
124 throw new IllegalStateException(String
.format(message
, list
.size()));
130 public NamedArea
getAreaByTdwgAbbreviation(String tdwgAbbreviation
) {
131 if (StringUtils
.isBlank(tdwgAbbreviation
)){ //TDWG areas should always have a label
134 List
<NamedArea
> list
= dao
.getDefinedTermByIdInVocabulary(tdwgAbbreviation
, NamedArea
.uuidTdwgAreaVocabulary
, NamedArea
.class, null, null);
137 }else if (list
.size() == 1){
140 String message
= "There is more then 1 (%d) TDWG area with the same abbreviated label. This is forbidden. Check the state of your database.";
141 throw new IllegalStateException(String
.format(message
, list
.size()));
146 public <T
extends DefinedTermBase
> Pager
<T
> getGeneralizationOf(T definedTerm
, Integer pageSize
, Integer pageNumber
) {
147 Integer numberOfResults
= dao
.countGeneralizationOf(definedTerm
);
149 List
<T
> results
= new ArrayList
<T
>();
150 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
151 results
= dao
.getGeneralizationOf(definedTerm
, pageSize
, pageNumber
);
154 return new DefaultPagerImpl
<T
>(pageNumber
, numberOfResults
, pageSize
, results
);
158 public <T
extends DefinedTermBase
> Pager
<T
> getIncludes(Collection
<T
> definedTerms
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
159 Integer numberOfResults
= dao
.countIncludes(definedTerms
);
161 List
<T
> results
= new ArrayList
<T
>();
162 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
163 results
= dao
.getIncludes(definedTerms
, pageSize
, pageNumber
,propertyPaths
);
166 return new DefaultPagerImpl
<T
>(pageNumber
, numberOfResults
, pageSize
, results
);
170 public Pager
<Media
> getMedia(DefinedTermBase definedTerm
, Integer pageSize
, Integer pageNumber
) {
171 Integer numberOfResults
= dao
.countMedia(definedTerm
);
173 List
<Media
> results
= new ArrayList
<Media
>();
174 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
175 results
= dao
.getMedia(definedTerm
, pageSize
, pageNumber
);
178 return new DefaultPagerImpl
<Media
>(pageNumber
, numberOfResults
, pageSize
, results
);
182 public <T
extends DefinedTermBase
> Pager
<T
> getPartOf(Set
<T
> definedTerms
,Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
183 Integer numberOfResults
= dao
.countPartOf(definedTerms
);
185 List
<T
> results
= new ArrayList
<T
>();
186 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
187 results
= dao
.getPartOf(definedTerms
, pageSize
, pageNumber
, propertyPaths
);
190 return new DefaultPagerImpl
<T
>(pageNumber
, numberOfResults
, pageSize
, results
);
194 public Pager
<NamedArea
> list(NamedAreaLevel level
, NamedAreaType type
, Integer pageSize
, Integer pageNumber
,
195 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
196 Integer numberOfResults
= dao
.count(level
, type
);
198 List
<NamedArea
> results
= new ArrayList
<NamedArea
>();
199 if (numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
200 results
= dao
.list(level
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
203 return new DefaultPagerImpl
<NamedArea
>(pageNumber
, numberOfResults
, pageSize
, results
);
207 public <T
extends DefinedTermBase
> Pager
<T
> findByRepresentationText(String label
, Class
<T
> clazz
, Integer pageSize
, Integer pageNumber
) {
208 Integer numberOfResults
= dao
.countDefinedTermByRepresentationText(label
,clazz
);
210 List
<T
> results
= new ArrayList
<T
>();
211 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
212 results
= dao
.getDefinedTermByRepresentationText(label
, clazz
, pageSize
, pageNumber
);
215 return new DefaultPagerImpl
<T
>(pageNumber
, numberOfResults
, pageSize
, results
);
219 public <T
extends DefinedTermBase
> Pager
<T
> findByRepresentationAbbreviation(String abbrev
, Class
<T
> clazz
, Integer pageSize
, Integer pageNumber
) {
220 Integer numberOfResults
= dao
.countDefinedTermByRepresentationAbbrev(abbrev
,clazz
);
222 List
<T
> results
= new ArrayList
<T
>();
223 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
224 results
= dao
.getDefinedTermByRepresentationAbbrev(abbrev
, clazz
, pageSize
, pageNumber
);
227 return new DefaultPagerImpl
<T
>(pageNumber
, numberOfResults
, pageSize
, results
);
231 public List
<LanguageString
> getAllLanguageStrings(int limit
, int start
) {
232 return languageStringDao
.list(limit
, start
);
236 public List
<Representation
> getAllRepresentations(int limit
, int start
) {
237 return representationDao
.list(limit
,start
);
241 public UUID
saveLanguageData(LanguageStringBase languageData
) {
242 return languageStringBaseDao
.save(languageData
).getUuid();
246 /** @deprecated use {@link #delete(DefinedTermBase, TermDeletionConfigurator)} instead
247 * to allow DeleteResult return type*/
250 public DeleteResult
delete(DefinedTermBase term
){
251 DeleteResult result
= new DeleteResult();
253 TermDeletionConfigurator defaultConfig
= new TermDeletionConfigurator();
254 result
= delete(term
, defaultConfig
);
260 @Transactional(readOnly
= false)
261 public DeleteResult
delete(UUID termUuid
){
262 DeleteResult result
= new DeleteResult();
264 TermDeletionConfigurator defaultConfig
= new TermDeletionConfigurator();
265 result
= delete(dao
.load(termUuid
), defaultConfig
);
270 public DeleteResult
delete(DefinedTermBase term
, TermDeletionConfigurator config
){
272 config
= new TermDeletionConfigurator();
274 // boolean isInternal = config.isInternal();
276 Set
<DefinedTermBase
> termsToSave
= new HashSet
<DefinedTermBase
>();
278 DeleteResult result
= isDeletable(term
.getUuid(), config
);
279 //CdmBase.deproxy(dao.merge(term), DefinedTermBase.class);
282 Set
<DefinedTermBase
> specificTerms
= term
.getGeneralizationOf();
283 if (specificTerms
.size()>0){
284 if (config
.isDeleteGeneralizationOfRelations()){
285 DefinedTermBase generalTerm
= term
.getKindOf();
286 for (DefinedTermBase specificTerm
: specificTerms
){
287 term
.removeGeneralization(specificTerm
);
288 if (generalTerm
!= null){
289 generalTerm
.addGeneralizationOf(specificTerm
);
290 termsToSave
.add(generalTerm
);
294 //TODO Exception type
295 String message
= "This term has specifing terms. Move or delete specifiing terms prior to delete or change delete configuration.";
296 result
.addRelatedObjects(specificTerms
);
298 Exception ex
= new DataChangeNoRollbackException(message
);
299 result
.addException(ex
);
304 DefinedTermBase generalTerm
= term
.getKindOf();
305 if (generalTerm
!= null){
306 if (config
.isDeleteKindOfRelations()){
307 generalTerm
.removeGeneralization(term
);
309 //TODO Exception type
310 String message
= "This term is kind of another term. Move or delete kind of relationship prior to delete or change delete configuration.";
311 result
.addRelatedObject(generalTerm
);
313 DataChangeNoRollbackException ex
= new DataChangeNoRollbackException(message
);
314 result
.addException(ex
);
320 DefinedTermBase parentTerm
= term
.getPartOf();
321 if (parentTerm
!= null){
322 if (! config
.isDeletePartOfRelations()){
323 //TODO Exception type
324 String message
= "This term is included in another term. Remove from parent term prior to delete or change delete configuration.";
325 result
.addRelatedObject(parentTerm
);
327 DataChangeNoRollbackException ex
= new DataChangeNoRollbackException(message
);
328 result
.addException(ex
);
334 Set
<DefinedTermBase
> includedTerms
= term
.getIncludes();
335 if (includedTerms
.size()> 0){
336 // if (config.isDeleteIncludedTerms()){
337 // for (DefinedTermBase includedTerm: includedTerms){
338 // config.setCheck(true);
339 // DeleteResult includedResult = this.delete(includedTerm, config);
340 //// config.setCheck(isCheck);
341 // result.includeResult(includedResult);
344 if (config
.isDeleteIncludedRelations()){
345 DefinedTermBase parent
= term
.getPartOf();
346 for (DefinedTermBase includedTerm
: includedTerms
){
347 term
.removeIncludes(includedTerm
);
349 parent
.addIncludes(includedTerm
);
350 termsToSave
.add(parent
);
354 //TODO Exception type
355 String message
= "This term includes other terms. Move or delete included terms prior to delete or change delete configuration.";
356 result
.addRelatedObjects(includedTerms
);
358 Exception ex
= new DataChangeNoRollbackException(message
);
359 result
.addException(ex
);
364 if (parentTerm
!= null){
365 if (config
.isDeletePartOfRelations()){
366 parentTerm
.removeIncludes(term
);
367 termsToSave
.add(parentTerm
);
369 //handelede before "included in"
377 TermVocabulary voc
= term
.getVocabulary();
379 voc
.removeTerm(term
);
382 if (true /*!config.isInternal()*/){
384 dao
.saveOrUpdateAll(termsToSave
);
385 // for (DeleteResult.PersistPair persistPair : result.getObjectsToDelete()){
386 // persistPair.dao.delete(persistPair.objectToPersist);
388 // for (DeleteResult.PersistPair persistPair : result.getObjectsToSave()){
389 // persistPair.dao.saveOrUpdate(persistPair.objectToPersist);
394 } catch (DataChangeNoRollbackException e
) {
395 result
.setStatus(Status
.ERROR
);
401 @Transactional(readOnly
= false)
402 public DeleteResult
delete(UUID termUuid
, TermDeletionConfigurator config
){
403 return delete(dao
.load(termUuid
), config
);
407 @Transactional(readOnly
= false)
408 public void updateTitleCache(Class
<?
extends DefinedTermBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<DefinedTermBase
> cacheStrategy
, IProgressMonitor monitor
) {
409 //TODO shouldnt this be TermBase instead of DefinedTermBase
411 clazz
= DefinedTermBase
.class;
413 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
417 public DeleteResult
isDeletable(UUID termUuid
, DeleteConfiguratorBase config
){
418 DeleteResult result
= new DeleteResult();
419 TermBase term
= load(termUuid
);
420 Set
<CdmBase
> references
= commonService
.getReferencingObjectsForDeletion(term
);
421 if (references
!= null){
422 result
.addRelatedObjects(references
);
423 Iterator
<CdmBase
> iterator
= references
.iterator();
425 while (iterator
.hasNext()){
426 ref
= iterator
.next();
427 if (ref
instanceof TermVocabulary
){
428 result
.getRelatedObjects().remove(ref
);
431 String message
= "An object of " + ref
.getClass().getName() + " with ID " + ref
.getId() + " is referencing the object" ;
432 result
.addException(new ReferencedObjectUndeletableException(message
));
442 @Transactional(readOnly
= false)
443 public Map
<UUID
, Representation
> saveOrUpdateRepresentations(Collection
<Representation
> representations
){
444 return representationDao
.saveOrUpdateAll(representations
);
448 @Transactional(readOnly
= true)
449 public List
<UuidAndTitleCache
<NamedArea
>> getUuidAndTitleCache(List
<TermVocabulary
> vocs
, Integer limit
, String pattern
, Language lang
) {
450 List
<NamedArea
> areas
= dao
.getUuidAndTitleCache(vocs
, limit
, pattern
);
452 List
<UuidAndTitleCache
<NamedArea
>> result
= new ArrayList();
453 UuidAndTitleCache
<NamedArea
> uuidAndTitleCache
;
454 for (NamedArea area
: areas
){
455 uuidAndTitleCache
= new UuidAndTitleCache
<>(area
.getUuid(), area
.getId(), area
.labelWithLevel(area
, lang
));
456 result
.add(uuidAndTitleCache
);