3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.cdm
.api
.service
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collection
;
15 import java
.util
.Collections
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
20 import java
.util
.UUID
;
22 import org
.apache
.log4j
.Logger
;
23 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
24 import org
.springframework
.stereotype
.Service
;
25 import org
.springframework
.transaction
.TransactionStatus
;
26 import org
.springframework
.transaction
.annotation
.Transactional
;
28 import eu
.etaxonomy
.cdm
.api
.service
.config
.ITaxonServiceConfigurator
;
29 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
30 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
31 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
32 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
33 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
34 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
35 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
36 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
37 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
38 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
39 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
40 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
41 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
42 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
43 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
44 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
45 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
46 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
47 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
48 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
49 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonomicTree
;
50 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
51 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IDescriptionDao
;
52 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
53 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
54 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonomicTreeDao
;
55 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
56 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
57 import eu
.etaxonomy
.cdm
.persistence
.query
.SelectMode
;
61 @Transactional(readOnly
= true)
62 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
63 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
66 private ITaxonNameDao nameDao
;
68 private ITaxonomicTreeDao taxonTreeDao
;
70 // @Qualifier("nonViralNameDaoHibernateImpl")
71 // private INonViralNameDao nonViralNameDao;
73 private IOrderedTermVocabularyDao orderedVocabularyDao
;
75 private IDescriptionDao descriptionDao
;
81 public TaxonServiceImpl(){
82 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
86 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getTaxonByUuid(java.util.UUID)
88 public TaxonBase
getTaxonByUuid(UUID uuid
) {
89 return super.findByUuid(uuid
);
93 * @see eu.etaxonomy.cdm.api.service.ITaxonService#saveTaxon(eu.etaxonomy.cdm.model.taxon.TaxonBase)
95 @Transactional(readOnly
= false)
96 public UUID
saveTaxon(TaxonBase taxon
) {
97 return super.saveCdmObject(taxon
);
100 //@Transactional(readOnly = false)
101 public UUID
saveTaxon(TaxonBase taxon
, TransactionStatus txStatus
) {
102 //return super.saveCdmObject(taxon, txStatus);
103 return super.saveCdmObject(taxon
);
108 * @see eu.etaxonomy.cdm.api.service.ITaxonService#saveTaxonAll(java.util.Collection)
110 @Transactional(readOnly
= false)
111 public Map
<UUID
, ?
extends TaxonBase
> saveTaxonAll(Collection
<?
extends TaxonBase
> taxonCollection
){
112 return saveCdmObjectAll(taxonCollection
);
116 * @see eu.etaxonomy.cdm.api.service.ITaxonService#removeTaxon(eu.etaxonomy.cdm.model.taxon.TaxonBase)
118 @Transactional(readOnly
= false)
119 public UUID
removeTaxon(TaxonBase taxon
) {
120 return super.removeCdmObject(taxon
);
123 public List
<TaxonBase
> searchTaxaByName(String name
, ReferenceBase sec
) {
124 return dao
.getTaxaByName(name
, sec
);
128 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxonBases(int, int)
130 public List
<TaxonBase
> getAllTaxonBases(int limit
, int start
){
131 return dao
.list(limit
, start
);
135 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
137 public List
<Taxon
> getAllTaxa(int limit
, int start
){
138 return dao
.getAllTaxa(limit
, start
);
142 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
144 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
145 return dao
.getAllSynonyms(limit
, start
);
150 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxonomicTrees(int, int)
152 public List
<TaxonomicTree
> getAllTaxonomicTrees(int limit
, int start
) {
153 return taxonTreeDao
.list(limit
, start
);
157 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getTaxonomicTreeByUuid(java.util.UUID)
159 public TaxonomicTree
getTaxonomicTreeByUuid(UUID uuid
){
160 return taxonTreeDao
.findByUuid(uuid
);
164 * @see eu.etaxonomy.cdm.api.service.ITaxonService#saveTaxonomicTree(eu.etaxonomy.cdm.model.taxon.TaxonomicTree)
166 @Transactional(readOnly
= false)
167 public UUID
saveTaxonomicTree(TaxonomicTree tree
){
168 return taxonTreeDao
.saveOrUpdate(tree
);
172 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.ReferenceBase)
174 public List
<Taxon
> getRootTaxa(ReferenceBase sec
){
175 return getRootTaxa(sec
, CdmFetch
.FETCH_CHILDTAXA(), true);
179 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.ReferenceBase, boolean)
181 public List
<Taxon
> getRootTaxa(ReferenceBase sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
182 if (cdmFetch
== null){
183 cdmFetch
= CdmFetch
.NO_FETCH();
185 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
189 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.ReferenceBase, boolean, boolean)
191 public List
<Taxon
> getRootTaxa(ReferenceBase sec
, boolean onlyWithChildren
,
192 boolean withMisapplications
) {
193 return dao
.getRootTaxa(sec
, null, onlyWithChildren
, withMisapplications
);
197 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.ReferenceBase, boolean, boolean)
199 public List
<Taxon
> getRootTaxa(Rank rank
, ReferenceBase sec
, boolean onlyWithChildren
,
200 boolean withMisapplications
, List
<String
> propertyPaths
) {
201 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
204 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
205 return dao
.getAllRelationships(limit
, start
);
208 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
210 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
211 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
212 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
213 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
214 return taxonRelTypeVocabulary
;
218 * @see eu.etaxonomy.cdm.api.service.ITaxonService#makeTaxonSynonym(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Taxon)
220 @Transactional(readOnly
= false)
221 public Synonym
makeTaxonSynonym(Taxon oldTaxon
, Taxon newAcceptedTaxon
, SynonymRelationshipType synonymType
, ReferenceBase citation
, String citationMicroReference
) {
222 if (oldTaxon
== null || newAcceptedTaxon
== null || oldTaxon
.getName() == null){
226 // Move oldTaxon to newTaxon
227 TaxonNameBase
<?
,?
> synonymName
= oldTaxon
.getName();
228 if (synonymType
== null){
229 if (synonymName
.isHomotypic(newAcceptedTaxon
.getName())){
230 synonymType
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
233 synonymType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
236 SynonymRelationship synRel
= newAcceptedTaxon
.addSynonymName(synonymName
, synonymType
, citation
, citationMicroReference
);
238 //Move Synonym Relations to new Taxon
239 for(SynonymRelationship synRelation
: oldTaxon
.getSynonymRelations()){
240 newAcceptedTaxon
.addSynonym(synRelation
.getSynonym(), synRelation
.getType(),
241 synRelation
.getCitation(), synRelation
.getCitationMicroReference());
244 //Move Taxon RelationShips to new Taxon
245 Set
<TaxonRelationship
> removableTaxonRels
= new HashSet
<TaxonRelationship
>();
246 for(TaxonRelationship taxonRelation
: oldTaxon
.getTaxonRelations()){
248 if (taxonRelation
.getType().equals(TaxonRelationshipType
.TAXONOMICALLY_INCLUDED_IN())){
249 if (taxonRelation
.getFromTaxon() == oldTaxon
){
250 removableTaxonRels
.add(taxonRelation
);
251 // oldTaxon.removeTaxonRelation(taxonRelation);
252 }else if(taxonRelation
.getToTaxon() == oldTaxon
){
253 newAcceptedTaxon
.addTaxonomicChild(taxonRelation
.getFromTaxon(), taxonRelation
.getCitation(), taxonRelation
.getCitationMicroReference());
254 removableTaxonRels
.add(taxonRelation
);
255 // oldTaxon.removeTaxonRelation(taxonRelation);
257 logger
.warn("Taxon is not part of its own Taxonrelationship");
261 if (taxonRelation
.getType().equals(TaxonRelationshipType
.MISAPPLIED_NAME_FOR())){
262 if (taxonRelation
.getFromTaxon() == oldTaxon
){
263 newAcceptedTaxon
.addMisappliedName(taxonRelation
.getToTaxon(), taxonRelation
.getCitation(), taxonRelation
.getCitationMicroReference());
264 removableTaxonRels
.add(taxonRelation
);
265 // oldTaxon.removeTaxonRelation(taxonRelation);
266 }else if(taxonRelation
.getToTaxon() == oldTaxon
){
267 newAcceptedTaxon
.addMisappliedName(taxonRelation
.getFromTaxon(), taxonRelation
.getCitation(), taxonRelation
.getCitationMicroReference());
268 removableTaxonRels
.add(taxonRelation
);
269 // oldTaxon.removeTaxonRelation(taxonRelation);
271 logger
.warn("Taxon is not part of its own Taxonrelationship");
274 //Concept Relationships
276 // if (taxonRelation.getType().equals(TaxonRelationshipType.MISAPPLIEDNAMEFOR())){
277 // if (taxonRelation.getFromTaxon() == oldTaxon){
278 // newAcceptedTaxon.addMisappliedName(taxonRelation.getToTaxon(), taxonRelation.getCitation(), taxonRelation.getCitationMicroReference());
279 // removableTaxonRels.add(taxonRelation);
280 // }else if(taxonRelation.getToTaxon() == oldTaxon){
281 // newAcceptedTaxon.addMisappliedName(taxonRelation.getFromTaxon(), taxonRelation.getCitation(), taxonRelation.getCitationMicroReference());
282 // removableTaxonRels.add(taxonRelation);
284 // logger.warn("Taxon is not part of its own Taxonrelationship");
289 for(TaxonRelationship taxonRel
: removableTaxonRels
) {
290 oldTaxon
.removeTaxonRelation(taxonRel
);
293 //Move Descriptions to new Taxon
294 for(TaxonDescription taxDescription
: oldTaxon
.getDescriptions()){
295 newAcceptedTaxon
.addDescription(taxDescription
);
298 this.dao
.saveOrUpdate(newAcceptedTaxon
);
300 // this.dao.delete(oldTaxon);
304 return synRel
.getSynonym();
308 public void generateTitleCache() {
309 generateTitleCache(true);
312 public void generateTitleCache(boolean forceProtected
) {
313 logger
.warn("generateTitleCache not yet fully implemented!");
314 // for (TaxonBase tb : taxonDao.getAllTaxa(null,null)){
315 // logger.warn("Old taxon title: " + tb.getTitleCache());
316 // if (forceProtected || !tb.isProtectedTitleCache() ){
317 // tb.setTitleCache(tb.generateTitle(), false);
318 // taxonDao.update(tb);
319 // logger.warn("New title: " + tb.getTitleCache());
326 protected void setDao(ITaxonDao dao
) {
330 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
331 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
333 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
334 if(numberOfResults
> 0) { // no point checking again
335 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
338 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
341 public Pager
<TaxonRelationship
> getRelatedTaxa(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
342 Integer numberOfResults
= dao
.countRelatedTaxa(taxon
, type
);
344 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
345 if(numberOfResults
> 0) { // no point checking again
346 results
= dao
.getRelatedTaxa(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
349 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
352 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
353 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
355 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
356 if(numberOfResults
> 0) { // no point checking again
357 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
360 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
363 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
364 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
365 return t
.getHomotypicSynonymsByHomotypicGroup();
368 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
369 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
370 List
<HomotypicalGroup
> hsgl
= t
.getHeterotypicSynonymyGroups();
371 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(hsgl
.size());
372 for(HomotypicalGroup hsg
: hsgl
){
373 heterotypicSynonymyGroups
.add(hsg
.getSynonymsInGroup(t
.getSec()));
375 return heterotypicSynonymyGroups
;
378 public Pager
<TaxonBase
> search(Class
<?
extends TaxonBase
> clazz
, String queryString
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
379 Integer numberOfResults
= dao
.count(clazz
,queryString
);
381 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
382 if(numberOfResults
> 0) { // no point checking again
383 results
= dao
.search(clazz
,queryString
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
386 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
390 public Pager
<IdentifiableEntity
> findTaxaAndNames(ITaxonServiceConfigurator configurator
) {
392 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
393 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
394 List
<TaxonBase
> taxa
= null;
398 int numberTaxaResults
= 0;
400 if (configurator
.isDoTaxa() && configurator
.isDoSynonyms()) {
401 taxa
= dao
.getTaxaByName(configurator
.getSearchString(),
402 configurator
.getMatchMode(), SelectMode
.ALL
, configurator
.getSec(),
403 configurator
.getPageSize(), configurator
.getPageNumber());
405 dao
.countTaxaByName(configurator
.getSearchString(),
406 configurator
.getMatchMode(), SelectMode
.ALL
, configurator
.getSec());
408 } else if(configurator
.isDoTaxa()) {
409 taxa
= dao
.getTaxaByName(configurator
.getSearchString(),
410 configurator
.getMatchMode(), SelectMode
.TAXA
, configurator
.getSec(),
411 configurator
.getPageSize(), configurator
.getPageNumber());
413 dao
.countTaxaByName(configurator
.getSearchString(),
414 configurator
.getMatchMode(), SelectMode
.TAXA
, configurator
.getSec());
416 } else if (configurator
.isDoSynonyms()) {
417 taxa
= dao
.getTaxaByName(configurator
.getSearchString(),
418 configurator
.getMatchMode(), SelectMode
.SYNONYMS
, configurator
.getSec(),
419 configurator
.getPageSize(), configurator
.getPageNumber());
421 dao
.countTaxaByName(configurator
.getSearchString(),
422 configurator
.getMatchMode(), SelectMode
.SYNONYMS
, configurator
.getSec());
425 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
427 results
.addAll(taxa
);
429 numberOfResults
+= numberTaxaResults
;
431 // Names without taxa
433 if (configurator
.isDoNamesWithoutTaxa()) {
434 int numberNameResults
= 0;
435 List
<?
extends TaxonNameBase
<?
,?
>> names
=
436 nameDao
.findByName(configurator
.getSearchString(), configurator
.getMatchMode(),
437 configurator
.getPageSize(), configurator
.getPageNumber(), null);
438 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
439 if (names
.size() > 0) {
440 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
441 if (taxonName
.getTaxonBases().size() == 0) {
442 results
.add(taxonName
);
446 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
447 numberOfResults
+= numberNameResults
;
451 // Taxa from common names
453 if (configurator
.isDoTaxaByCommonNames()) {
454 int numberCommonNameResults
= 0;
455 List
<CommonTaxonName
> commonTaxonNames
=
456 descriptionDao
.searchDescriptionByCommonName(configurator
.getSearchString(),
457 configurator
.getMatchMode(), configurator
.getPageSize(), configurator
.getPageNumber());
458 if (logger
.isDebugEnabled()) { logger
.debug(commonTaxonNames
.size() + " matching common name(s) found"); }
459 if (commonTaxonNames
.size() > 0) {
460 for (CommonTaxonName commonTaxonName
: commonTaxonNames
) {
461 DescriptionBase description
= commonTaxonName
.getInDescription();
462 description
= HibernateProxyHelper
.deproxy(description
, DescriptionBase
.class);
463 if (description
instanceof TaxonDescription
) {
464 TaxonDescription taxonDescription
= HibernateProxyHelper
.deproxy(description
, TaxonDescription
.class);
465 Taxon taxon
= taxonDescription
.getTaxon();
466 taxon
= HibernateProxyHelper
.deproxy(taxon
, Taxon
.class);
467 if (!results
.contains(taxon
) && !taxon
.isMisappliedName()) {
469 numberCommonNameResults
++;
472 logger
.warn("Description of " + commonTaxonName
.getName() + " is not an instance of TaxonDescription");
475 numberOfResults
+= numberCommonNameResults
;
479 Collections
.sort(results
);
480 return new DefaultPagerImpl
<IdentifiableEntity
>
481 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);