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
.Collections
;
15 import java
.util
.Comparator
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
19 import java
.util
.UUID
;
21 import org
.apache
.log4j
.Logger
;
22 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
23 import org
.springframework
.stereotype
.Service
;
24 import org
.springframework
.transaction
.annotation
.Transactional
;
26 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
27 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonNodeDeletionConfigurator
;
28 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonNodeDeletionConfigurator
.ChildHandling
;
29 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
30 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
31 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
32 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
33 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
34 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
35 import eu
.etaxonomy
.cdm
.model
.taxon
.ITaxonNodeComparator
;
36 import eu
.etaxonomy
.cdm
.model
.taxon
.ITaxonTreeNode
;
37 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
38 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
39 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
40 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
41 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
42 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
43 import eu
.etaxonomy
.cdm
.persistence
.dao
.initializer
.IBeanInitializer
;
44 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonNodeDao
;
48 * @created Apr 9, 2010
52 @Transactional(readOnly
= true)
53 public class TaxonNodeServiceImpl
extends AnnotatableServiceBase
<TaxonNode
, ITaxonNodeDao
> implements ITaxonNodeService
{
54 private static final Logger logger
= Logger
.getLogger(TaxonNodeServiceImpl
.class);
57 private IBeanInitializer defaultBeanInitializer
;
59 private Comparator
<?
super TaxonNode
> taxonNodeComparator
;
62 private ITaxonService taxonService
;
65 private IClassificationService classService
;
68 public void setTaxonNodeComparator(ITaxonNodeComparator
<?
super TaxonNode
> taxonNodeComparator
){
69 this.taxonNodeComparator
= (Comparator
<?
super TaxonNode
>) taxonNodeComparator
;
73 public List
<TaxonNode
> loadChildNodesOfTaxonNode(TaxonNode taxonNode
,
74 List
<String
> propertyPaths
, boolean recursive
) {
75 taxonNode
= dao
.load(taxonNode
.getUuid());
76 List
<TaxonNode
> childNodes
;
77 if (recursive
== true){
78 childNodes
= dao
.listChildrenOf(taxonNode
, null, null, null, recursive
);
80 childNodes
= new ArrayList
<TaxonNode
>(taxonNode
.getChildNodes());
82 Collections
.sort(childNodes
, taxonNodeComparator
);
83 defaultBeanInitializer
.initializeAll(childNodes
, propertyPaths
);
88 * @see eu.etaxonomy.cdm.api.service.ServiceBase#setDao(eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao)
92 protected void setDao(ITaxonNodeDao dao
) {
97 * @see eu.etaxonomy.cdm.api.service.ITaxonService#makeTaxonSynonym(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Taxon)
100 @Transactional(readOnly
= false)
101 public Synonym
makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode
, TaxonNode newAcceptedTaxonNode
, SynonymRelationshipType synonymRelationshipType
, Reference citation
, String citationMicroReference
) {
103 // TODO at the moment this method only moves synonym-, concept relations and descriptions to the new accepted taxon
104 // in a future version we also want to move cdm data like annotations, marker, so., but we will need a policy for that
105 if (oldTaxonNode
== null || newAcceptedTaxonNode
== null || oldTaxonNode
.getTaxon().getName() == null){
106 throw new IllegalArgumentException("A mandatory parameter was null.");
109 if(oldTaxonNode
.equals(newAcceptedTaxonNode
)){
110 throw new IllegalArgumentException("Taxon can not be made synonym of its own.");
115 Taxon oldTaxon
= (Taxon
) HibernateProxyHelper
.deproxy(oldTaxonNode
.getTaxon());
116 Taxon newAcceptedTaxon
= (Taxon
) HibernateProxyHelper
.deproxy(newAcceptedTaxonNode
.getTaxon());
118 // Move oldTaxon to newTaxon
119 //TaxonNameBase<?,?> synonymName = oldTaxon.getName();
120 TaxonNameBase
<?
,?
> synonymName
= (TaxonNameBase
)HibernateProxyHelper
.deproxy(oldTaxon
.getName());
121 HomotypicalGroup group
= synonymName
.getHomotypicalGroup();
122 if (synonymRelationshipType
== null){
123 if (synonymName
.isHomotypic(newAcceptedTaxon
.getName())){
124 synonymRelationshipType
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
126 synonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
130 //set homotypic group
131 HomotypicalGroup newAcceptedTaxonHomotypicalgroup
= newAcceptedTaxon
.getHomotypicGroup();
132 HibernateProxyHelper
.deproxy(newAcceptedTaxonHomotypicalgroup
);
133 HibernateProxyHelper
.deproxy(newAcceptedTaxon
.getName());
134 // Move Synonym Relations to new Taxon
135 SynonymRelationship synonmyRelationship
= newAcceptedTaxon
.addSynonymName(synonymName
,
136 synonymRelationshipType
, citation
, citationMicroReference
);
137 HomotypicalGroup homotypicalGroupAcceptedTaxon
= synonmyRelationship
.getSynonym().getHomotypicGroup();
138 // Move Synonym Relations to new Taxon
139 // From ticket 3163 we can move taxon with accepted name having homotypic synonyms
140 List
<Synonym
> synonymsInHomotypicalGroup
= null;
142 //the synonyms of the homotypical group of the old taxon
143 if (synonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF())){
144 synonymsInHomotypicalGroup
= oldTaxon
.getSynonymsInGroup(group
);
147 for(SynonymRelationship synRelation
: oldTaxon
.getSynonymRelations()){
148 SynonymRelationshipType srt
;
149 if(synRelation
.getSynonym().getName().getHomotypicalGroup()!= null
150 && synRelation
.getSynonym().getName().getHomotypicalGroup().equals(newAcceptedTaxon
.getName().getHomotypicalGroup())) {
151 srt
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
152 } else if(synRelation
.getType() != null && synRelation
.getType().equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF())) {
153 if (synonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF())){
154 srt
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
156 srt
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
159 srt
= synRelation
.getType();
163 newAcceptedTaxon
.addSynonym(synRelation
.getSynonym(),
165 synRelation
.getCitation(),
166 synRelation
.getCitationMicroReference());
168 /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF())){
169 homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
179 if(oldTaxonNode
.getChildNodes() != null && oldTaxonNode
.getChildNodes().size() != 0){
180 for(TaxonNode childNode
: oldTaxonNode
.getChildNodes()){
181 newAcceptedTaxonNode
.addChildNode(childNode
, childNode
.getReference(), childNode
.getMicroReference()); // childNode.getSynonymToBeUsed()
185 //Move Taxon RelationShips to new Taxon
186 Set
<TaxonRelationship
> obsoleteTaxonRelationships
= new HashSet
<TaxonRelationship
>();
187 for(TaxonRelationship taxonRelationship
: oldTaxon
.getTaxonRelations()){
188 Taxon fromTaxon
= (Taxon
) HibernateProxyHelper
.deproxy(taxonRelationship
.getFromTaxon());
189 Taxon toTaxon
= (Taxon
) HibernateProxyHelper
.deproxy(taxonRelationship
.getToTaxon());
190 if (fromTaxon
== oldTaxon
){
191 newAcceptedTaxon
.addTaxonRelation(taxonRelationship
.getToTaxon(), taxonRelationship
.getType(),
192 taxonRelationship
.getCitation(), taxonRelationship
.getCitationMicroReference());
194 }else if(toTaxon
== oldTaxon
){
195 fromTaxon
.addTaxonRelation(newAcceptedTaxon
, taxonRelationship
.getType(),
196 taxonRelationship
.getCitation(), taxonRelationship
.getCitationMicroReference());
197 taxonService
.saveOrUpdate(fromTaxon
);
200 logger
.warn("Taxon is not part of its own Taxonrelationship");
202 // Remove old relationships
204 fromTaxon
.removeTaxonRelation(taxonRelationship
);
205 toTaxon
.removeTaxonRelation(taxonRelationship
);
206 taxonRelationship
.setToTaxon(null);
207 taxonRelationship
.setFromTaxon(null);
211 //Move descriptions to new taxon
212 List
<TaxonDescription
> descriptions
= new ArrayList
<TaxonDescription
>( oldTaxon
.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())
213 for(TaxonDescription description
: descriptions
){
214 String message
= "Description copied from former accepted taxon: %s (Old title: %s)";
215 message
= String
.format(message
, oldTaxon
.getTitleCache(), description
.getTitleCache());
216 description
.setTitleCache(message
, true);
217 newAcceptedTaxon
.addDescription(description
);
219 taxonService
.update(newAcceptedTaxon
);
220 TaxonDeletionConfigurator conf
= new TaxonDeletionConfigurator();
221 conf
.setDeleteSynonymsIfPossible(false);
222 List
<String
> deleteMessages
= taxonService
.isDeletable(oldTaxon
, conf
);
223 // conf.setDeleteNameIfPossible(false);
224 if (deleteMessages
.isEmpty()){
225 String uuidString
= taxonService
.deleteTaxon(oldTaxon
, conf
, null);
226 logger
.debug(uuidString
);
228 TaxonNodeDeletionConfigurator config
= new TaxonNodeDeletionConfigurator();
229 config
.setDeleteTaxon(false);
230 conf
.setTaxonNodeConfig(config
);
231 deleteTaxonNode(oldTaxonNode
, conf
);
234 //oldTaxonNode.delete();
235 return synonmyRelationship
.getSynonym();
239 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNodes(java.util.List)
242 @Transactional(readOnly
= false)
243 public List
<UUID
> deleteTaxonNodes(Set
<ITaxonTreeNode
> nodes
, TaxonDeletionConfigurator config
) {
245 config
= new TaxonDeletionConfigurator();
247 List
<UUID
> deletedUUIDs
= new ArrayList
<UUID
>();
248 Classification classification
= null;
249 for (ITaxonTreeNode treeNode
:nodes
){
250 if (treeNode
!= null){
251 if (treeNode
instanceof TaxonNode
){
253 taxonNode
= HibernateProxyHelper
.deproxy(treeNode
, TaxonNode
.class);
255 //check whether the node has children or the children are already deleted
256 if(taxonNode
.hasChildNodes()){
257 Set
<ITaxonTreeNode
> children
= new HashSet
<ITaxonTreeNode
> ();
258 List
<TaxonNode
> childNodesList
= taxonNode
.getChildNodes();
259 children
.addAll(childNodesList
);
260 int compare
= config
.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling
.DELETE
);
261 boolean childHandling
= (compare
== 0)?
true: false;
263 boolean changeDeleteTaxon
= false;
264 if (!config
.getTaxonNodeConfig().isDeleteTaxon()){
265 config
.getTaxonNodeConfig().setDeleteTaxon(true);
266 changeDeleteTaxon
= true;
268 deleteTaxonNodes(children
, config
);
269 if (changeDeleteTaxon
){
270 config
.getTaxonNodeConfig().setDeleteTaxon(false);
274 //move the children to the parent
275 TaxonNode parent
= taxonNode
.getParent();
276 for (TaxonNode child
: childNodesList
){
277 parent
.addChildNode(child
, child
.getReference(), child
.getMicroReference());
283 classification
= taxonNode
.getClassification();
285 if (classification
.getRootNode().equals(taxonNode
)){
286 classification
.removeRootNode();
287 classification
= null;
288 }else if (classification
.getChildNodes().contains(taxonNode
)){
289 Taxon taxon
= taxonNode
.getTaxon();
290 classification
.deleteChildNode(taxonNode
);
294 if (config
.getTaxonNodeConfig().isDeleteTaxon()){
295 TaxonDeletionConfigurator configNew
= new TaxonDeletionConfigurator();
296 configNew
.setDeleteTaxonNodes(false);
297 taxonService
.deleteTaxon(taxon
, configNew
, classification
);
300 classification
= null;
303 classification
= null;
304 Taxon taxon
= taxonNode
.getTaxon();
307 taxonNode
.getTaxon().removeTaxonNode(taxonNode
);
308 if (config
.getTaxonNodeConfig().isDeleteTaxon()){
309 TaxonDeletionConfigurator configNew
= new TaxonDeletionConfigurator();
310 configNew
.setDeleteTaxonNodes(false);
311 taxonService
.deleteTaxon(taxon
, configNew
, classification
);
317 UUID uuid
= dao
.delete(taxonNode
);
318 logger
.debug("Deleted node " +uuid
.toString());
320 classification
= (Classification
) treeNode
;
324 deletedUUIDs
.add(treeNode
.getUuid());
328 if (classification
!= null){
329 classService
.delete(classification
);
335 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNode(java.util.List)
338 @Transactional(readOnly
= false)
339 public String
deleteTaxonNode(TaxonNode node
, TaxonDeletionConfigurator config
) {
340 Taxon taxon
= (Taxon
)HibernateProxyHelper
.deproxy(node
.getTaxon());
342 config
= new TaxonDeletionConfigurator();
344 if (config
.getTaxonNodeConfig().isDeleteTaxon()){
345 return taxonService
.deleteTaxon(taxon
, config
, node
.getClassification());
347 taxon
.removeTaxonNode(node
);
349 return node
.getUuid().toString();
355 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#listAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification, int, int)
358 public List
<TaxonNode
> listAllNodesForClassification(Classification classification
, Integer start
, Integer end
) {
359 return dao
.getTaxonOfAcceptedTaxaByClassification(classification
, start
, end
);
363 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#countAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification)
366 public int countAllNodesForClassification(Classification classification
) {
367 return dao
.countTaxonOfAcceptedTaxaByClassification(classification
);