move taxon to homotypical synonym fixed
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonNodeServiceImpl.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
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.
9 */
10
11 package eu.etaxonomy.cdm.api.service;
12
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;
18 import java.util.Set;
19 import java.util.UUID;
20
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;
25
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;
47
48 /**
49 * @author n.hoffmann
50 * @created Apr 9, 2010
51 * @version 1.0
52 */
53 @Service
54 @Transactional(readOnly = true)
55 public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITaxonNodeDao> implements ITaxonNodeService{
56 private static final Logger logger = Logger.getLogger(TaxonNodeServiceImpl.class);
57
58 @Autowired
59 private IBeanInitializer defaultBeanInitializer;
60
61 private Comparator<? super TaxonNode> taxonNodeComparator;
62
63 @Autowired
64 private ITaxonService taxonService;
65
66 @Autowired
67 private IClassificationService classService;
68
69 @Autowired
70 public void setTaxonNodeComparator(ITaxonNodeComparator<? super TaxonNode> taxonNodeComparator){
71 this.taxonNodeComparator = (Comparator<? super TaxonNode>) taxonNodeComparator;
72 }
73
74 @Override
75 public TaxonNode getTaxonNodeByUuid(UUID uuid) {
76 return dao.findByUuid(uuid);
77 }
78
79 @Override
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);
86 return childNodes;
87 }
88
89 /* (non-Javadoc)
90 * @see eu.etaxonomy.cdm.api.service.ServiceBase#setDao(eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao)
91 */
92 @Override
93 @Autowired
94 protected void setDao(ITaxonNodeDao dao) {
95 this.dao = dao;
96 }
97
98 /* (non-Javadoc)
99 * @see eu.etaxonomy.cdm.api.service.ITaxonService#makeTaxonSynonym(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Taxon)
100 */
101 @Override
102 @Transactional(readOnly = false)
103 public Synonym makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode, SynonymRelationshipType synonymRelationshipType, Reference citation, String citationMicroReference) throws DataChangeNoRollbackException {
104
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.");
109 }
110
111 if(oldTaxonNode.equals(newAcceptedTaxonNode)){
112 throw new IllegalArgumentException("Taxon can not be made synonym of its own.");
113 }
114
115 Taxon oldTaxon = (Taxon) HibernateProxyHelper.deproxy(oldTaxonNode.getTaxon());
116 Taxon newAcceptedTaxon = (Taxon) HibernateProxyHelper.deproxy(newAcceptedTaxonNode.getTaxon());
117
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();
125 }else{
126 synonymRelationshipType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
127 }
128 }
129
130 //set homotypic group
131
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;
138
139 //the synonyms of the homotypical group of the old taxon
140 if (synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
141 synonymsInHomotypicalGroup = oldTaxon.getSynonymsInGroup(group);
142 }
143
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();
152 } else{
153 srt = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
154 }
155 } else {
156 srt = synRelation.getType();
157
158 }
159
160 newAcceptedTaxon.addSynonym(synRelation.getSynonym(),
161 srt,
162 synRelation.getCitation(),
163 synRelation.getCitationMicroReference());
164
165 /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF())){
166 homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
167 }*/
168
169 }
170
171
172
173
174
175 // CHILD NODES
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()
179 }
180 }
181
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());
190
191 }else if(toTaxon == oldTaxon){
192 fromTaxon.addTaxonRelation(newAcceptedTaxon, taxonRelationship.getType(),
193 taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
194 taxonService.saveOrUpdate(fromTaxon);
195
196 }else{
197 logger.warn("Taxon is not part of its own Taxonrelationship");
198 }
199 // Remove old relationships
200
201 fromTaxon.removeTaxonRelation(taxonRelationship);
202 toTaxon.removeTaxonRelation(taxonRelationship);
203 taxonRelationship.setToTaxon(null);
204 taxonRelationship.setFromTaxon(null);
205 }
206
207
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);
215 }
216
217 TaxonDeletionConfigurator conf = new TaxonDeletionConfigurator();
218 conf.setDeleteSynonymsIfPossible(false);
219 // conf.setDeleteNameIfPossible(false);
220 taxonService.deleteTaxon(oldTaxon, conf, null);
221
222 //oldTaxonNode.delete();
223 return synonmyRelationship.getSynonym();
224 }
225
226 /* (non-Javadoc)
227 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNodes(java.util.List)
228 */
229 @Override
230 @Transactional(readOnly = false)
231 public List<UUID> deleteTaxonNodes(Set<ITaxonTreeNode> nodes, TaxonDeletionConfigurator config) throws DataChangeNoRollbackException{
232 if (config == null){
233 config = new TaxonDeletionConfigurator();
234 }
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){
240 TaxonNode taxonNode;
241 taxonNode = (TaxonNode)HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);
242
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;
250 if (childHandling){
251 boolean changeDeleteTaxon = false;
252 if (!config.getTaxonNodeConfig().isDeleteTaxon()){
253 config.getTaxonNodeConfig().setDeleteTaxon(true);
254 changeDeleteTaxon = true;
255 }
256 deleteTaxonNodes(children, config);
257 if (changeDeleteTaxon){
258 config.getTaxonNodeConfig().setDeleteTaxon(false);
259 }
260
261 } else {
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());
266 }
267
268 }
269 }
270
271 classification = taxonNode.getClassification();
272
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);
279 //node is rootNode
280 if (taxon != null){
281
282 if (config.getTaxonNodeConfig().isDeleteTaxon()){
283 TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
284 configNew.setDeleteTaxonNodes(false);
285 taxonService.deleteTaxon(taxon, configNew, classification);
286 }
287 }
288 classification = null;
289
290 }else {
291 classification = null;
292 Taxon taxon = taxonNode.getTaxon();
293 //node is rootNode
294 if (taxon != null){
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);
300 }
301 }
302
303 }
304
305 dao.delete(taxonNode);
306 }else {
307 classification = (Classification) treeNode;
308
309 }
310
311 deletedUUIDs.add(treeNode.getUuid());
312
313 }
314 }
315 if (classification != null){
316 classService.delete(classification);
317 }
318 return deletedUUIDs;
319
320 }
321 /* (non-Javadoc)
322 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNode(java.util.List)
323 */
324 @Override
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());
329
330 return node.getUuid();
331 }
332
333
334 }