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
.api
.service
.exception
.DataChangeNoRollbackException
;
30 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
31 import eu
.etaxonomy
.cdm
.model
.common
.ITreeNode
;
32 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
33 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
34 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
35 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
36 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
37 import eu
.etaxonomy
.cdm
.model
.taxon
.ITaxonNodeComparator
;
38 import eu
.etaxonomy
.cdm
.model
.taxon
.ITaxonTreeNode
;
39 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
40 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
41 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
42 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
43 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
44 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
45 import eu
.etaxonomy
.cdm
.persistence
.dao
.initializer
.IBeanInitializer
;
46 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonNodeDao
;
50 * @created Apr 9, 2010
54 @Transactional(readOnly
= true)
55 public class TaxonNodeServiceImpl
extends AnnotatableServiceBase
<TaxonNode
, ITaxonNodeDao
> implements ITaxonNodeService
{
56 private static final Logger logger
= Logger
.getLogger(TaxonNodeServiceImpl
.class);
59 private IBeanInitializer defaultBeanInitializer
;
61 private Comparator
<?
super TaxonNode
> taxonNodeComparator
;
64 private ITaxonService taxonService
;
67 private IClassificationService classService
;
70 public void setTaxonNodeComparator(ITaxonNodeComparator
<?
super TaxonNode
> taxonNodeComparator
){
71 this.taxonNodeComparator
= (Comparator
<?
super TaxonNode
>) taxonNodeComparator
;
75 public TaxonNode
getTaxonNodeByUuid(UUID uuid
) {
76 return dao
.findByUuid(uuid
);
80 public List
<TaxonNode
> loadChildNodesOfTaxonNode(TaxonNode taxonNode
,
81 List
<String
> propertyPaths
) {
82 taxonNode
= dao
.load(taxonNode
.getUuid());
83 List
<TaxonNode
> childNodes
= new ArrayList
<TaxonNode
>(taxonNode
.getChildNodes());
84 Collections
.sort(childNodes
, taxonNodeComparator
);
85 defaultBeanInitializer
.initializeAll(childNodes
, propertyPaths
);
90 * @see eu.etaxonomy.cdm.api.service.ServiceBase#setDao(eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao)
94 protected void setDao(ITaxonNodeDao dao
) {
99 * @see eu.etaxonomy.cdm.api.service.ITaxonService#makeTaxonSynonym(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Taxon)
102 @Transactional(readOnly
= false)
103 public Synonym
makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode
, TaxonNode newAcceptedTaxonNode
, SynonymRelationshipType synonymRelationshipType
, Reference citation
, String citationMicroReference
) throws DataChangeNoRollbackException
{
105 // TODO at the moment this method only moves synonym-, concept relations and descriptions to the new accepted taxon
106 // in a future version we also want to move cdm data like annotations, marker, so., but we will need a policy for that
107 if (oldTaxonNode
== null || newAcceptedTaxonNode
== null || oldTaxonNode
.getTaxon().getName() == null){
108 throw new IllegalArgumentException("A mandatory parameter was null.");
111 if(oldTaxonNode
.equals(newAcceptedTaxonNode
)){
112 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
132 SynonymRelationship synonmyRelationship
= newAcceptedTaxon
.addSynonymName(synonymName
,
133 synonymRelationshipType
, citation
, citationMicroReference
);
134 HomotypicalGroup homotypicalGroupAcceptedTaxon
= synonmyRelationship
.getSynonym().getHomotypicGroup();
135 // Move Synonym Relations to new Taxon
136 // From ticket 3163 we can move taxon with accepted name having homotypic synonyms
137 List
<Synonym
> synonymsInHomotypicalGroup
= null;
139 //the synonyms of the homotypical group of the old taxon
140 if (synonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF())){
141 synonymsInHomotypicalGroup
= oldTaxon
.getSynonymsInGroup(group
);
144 for(SynonymRelationship synRelation
: oldTaxon
.getSynonymRelations()){
145 SynonymRelationshipType srt
;
146 if(synRelation
.getSynonym().getName().getHomotypicalGroup()!= null
147 && synRelation
.getSynonym().getName().getHomotypicalGroup().equals(newAcceptedTaxon
.getName().getHomotypicalGroup())) {
148 srt
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
149 } else if(synRelation
.getType() != null && synRelation
.getType().equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF())) {
150 if (synonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF())){
151 srt
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
153 srt
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
156 srt
= synRelation
.getType();
160 newAcceptedTaxon
.addSynonym(synRelation
.getSynonym(),
162 synRelation
.getCitation(),
163 synRelation
.getCitationMicroReference());
165 /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF())){
166 homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
176 if(oldTaxonNode
.getChildNodes() != null && oldTaxonNode
.getChildNodes().size() != 0){
177 for(TaxonNode childNode
: oldTaxonNode
.getChildNodes()){
178 newAcceptedTaxonNode
.addChildNode(childNode
, childNode
.getReference(), childNode
.getMicroReference()); // childNode.getSynonymToBeUsed()
182 //Move Taxon RelationShips to new Taxon
183 Set
<TaxonRelationship
> obsoleteTaxonRelationships
= new HashSet
<TaxonRelationship
>();
184 for(TaxonRelationship taxonRelationship
: oldTaxon
.getTaxonRelations()){
185 Taxon fromTaxon
= (Taxon
) HibernateProxyHelper
.deproxy(taxonRelationship
.getFromTaxon());
186 Taxon toTaxon
= (Taxon
) HibernateProxyHelper
.deproxy(taxonRelationship
.getToTaxon());
187 if (fromTaxon
== oldTaxon
){
188 newAcceptedTaxon
.addTaxonRelation(taxonRelationship
.getToTaxon(), taxonRelationship
.getType(),
189 taxonRelationship
.getCitation(), taxonRelationship
.getCitationMicroReference());
191 }else if(toTaxon
== oldTaxon
){
192 fromTaxon
.addTaxonRelation(newAcceptedTaxon
, taxonRelationship
.getType(),
193 taxonRelationship
.getCitation(), taxonRelationship
.getCitationMicroReference());
194 taxonService
.saveOrUpdate(fromTaxon
);
197 logger
.warn("Taxon is not part of its own Taxonrelationship");
199 // Remove old relationships
201 fromTaxon
.removeTaxonRelation(taxonRelationship
);
202 toTaxon
.removeTaxonRelation(taxonRelationship
);
203 taxonRelationship
.setToTaxon(null);
204 taxonRelationship
.setFromTaxon(null);
208 //Move descriptions to new taxon
209 List
<TaxonDescription
> descriptions
= new ArrayList
<TaxonDescription
>( oldTaxon
.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())
210 for(TaxonDescription description
: descriptions
){
211 String message
= "Description copied from former accepted taxon: %s (Old title: %s)";
212 message
= String
.format(message
, oldTaxon
.getTitleCache(), description
.getTitleCache());
213 description
.setTitleCache(message
, true);
214 newAcceptedTaxon
.addDescription(description
);
217 TaxonDeletionConfigurator conf
= new TaxonDeletionConfigurator();
218 conf
.setDeleteSynonymsIfPossible(false);
219 // conf.setDeleteNameIfPossible(false);
220 taxonService
.deleteTaxon(oldTaxon
, conf
, null);
222 //oldTaxonNode.delete();
223 return synonmyRelationship
.getSynonym();
227 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNodes(java.util.List)
230 @Transactional(readOnly
= false)
231 public List
<UUID
> deleteTaxonNodes(Set
<ITaxonTreeNode
> nodes
, TaxonDeletionConfigurator config
) throws DataChangeNoRollbackException
{
233 config
= new TaxonDeletionConfigurator();
235 List
<UUID
> deletedUUIDs
= new ArrayList
<UUID
>();
236 Classification classification
= null;
237 for (ITaxonTreeNode treeNode
:nodes
){
238 if (treeNode
!= null){
239 if (treeNode
instanceof TaxonNode
){
241 taxonNode
= (TaxonNode
)HibernateProxyHelper
.deproxy(treeNode
, TaxonNode
.class);
243 //check whether the node has children or the children are already deleted
244 if(taxonNode
.hasChildNodes()){
245 Set
<ITaxonTreeNode
> children
= new HashSet
<ITaxonTreeNode
> ();
246 List
<TaxonNode
> childNodesList
= taxonNode
.getChildNodes();
247 children
.addAll(childNodesList
);
248 int compare
= config
.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling
.DELETE
);
249 boolean childHandling
= (compare
== 0)?
true: false;
251 boolean changeDeleteTaxon
= false;
252 if (!config
.getTaxonNodeConfig().isDeleteTaxon()){
253 config
.getTaxonNodeConfig().setDeleteTaxon(true);
254 changeDeleteTaxon
= true;
256 deleteTaxonNodes(children
, config
);
257 if (changeDeleteTaxon
){
258 config
.getTaxonNodeConfig().setDeleteTaxon(false);
262 //move the children to the parent
263 TaxonNode parent
= taxonNode
.getParent();
264 for (TaxonNode child
: childNodesList
){
265 parent
.addChildNode(child
, child
.getReference(), child
.getMicroReference());
271 classification
= taxonNode
.getClassification();
273 if (classification
.getRootNode().equals(taxonNode
)){
274 classification
.removeRootNode();
275 classification
= null;
276 }else if (classification
.getChildNodes().contains(taxonNode
)){
277 Taxon taxon
= taxonNode
.getTaxon();
278 classification
.deleteChildNode(taxonNode
);
282 if (config
.getTaxonNodeConfig().isDeleteTaxon()){
283 TaxonDeletionConfigurator configNew
= new TaxonDeletionConfigurator();
284 configNew
.setDeleteTaxonNodes(false);
285 taxonService
.deleteTaxon(taxon
, configNew
, classification
);
288 classification
= null;
291 classification
= null;
292 Taxon taxon
= taxonNode
.getTaxon();
295 taxonNode
.getTaxon().removeTaxonNode(taxonNode
);
296 if (config
.getTaxonNodeConfig().isDeleteTaxon()){
297 TaxonDeletionConfigurator configNew
= new TaxonDeletionConfigurator();
298 configNew
.setDeleteTaxonNodes(false);
299 taxonService
.deleteTaxon(taxon
, configNew
, classification
);
305 dao
.delete(taxonNode
);
307 classification
= (Classification
) treeNode
;
311 deletedUUIDs
.add(treeNode
.getUuid());
315 if (classification
!= null){
316 classService
.delete(classification
);
322 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNode(java.util.List)
325 @Transactional(readOnly
= false)
326 public UUID
deleteTaxonNode(TaxonNode node
, TaxonDeletionConfigurator config
) throws DataChangeNoRollbackException
{
327 Taxon taxon
= (Taxon
)HibernateProxyHelper
.deproxy(node
.getTaxon());
328 taxonService
.deleteTaxon(taxon
, config
, node
.getClassification());
330 return node
.getUuid();