add description for loadChildNodesOfTaxonNode
[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.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;
45
46 /**
47 * @author n.hoffmann
48 * @created Apr 9, 2010
49 * @version 1.0
50 */
51 @Service
52 @Transactional(readOnly = true)
53 public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITaxonNodeDao> implements ITaxonNodeService{
54 private static final Logger logger = Logger.getLogger(TaxonNodeServiceImpl.class);
55
56 @Autowired
57 private IBeanInitializer defaultBeanInitializer;
58
59 private Comparator<? super TaxonNode> taxonNodeComparator;
60
61 @Autowired
62 private ITaxonService taxonService;
63
64 @Autowired
65 private IClassificationService classService;
66
67 @Autowired
68 public void setTaxonNodeComparator(ITaxonNodeComparator<? super TaxonNode> taxonNodeComparator){
69 this.taxonNodeComparator = (Comparator<? super TaxonNode>) taxonNodeComparator;
70 }
71
72 @Override
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);
79 }else{
80 childNodes = new ArrayList<TaxonNode>(taxonNode.getChildNodes());
81 }
82 Collections.sort(childNodes, taxonNodeComparator);
83 defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
84 return childNodes;
85 }
86
87 /* (non-Javadoc)
88 * @see eu.etaxonomy.cdm.api.service.ServiceBase#setDao(eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao)
89 */
90 @Override
91 @Autowired
92 protected void setDao(ITaxonNodeDao dao) {
93 this.dao = dao;
94 }
95
96 /* (non-Javadoc)
97 * @see eu.etaxonomy.cdm.api.service.ITaxonService#makeTaxonSynonym(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Taxon)
98 */
99 @Override
100 @Transactional(readOnly = false)
101 public Synonym makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode, SynonymRelationshipType synonymRelationshipType, Reference citation, String citationMicroReference) {
102
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.");
107 }
108
109 if(oldTaxonNode.equals(newAcceptedTaxonNode)){
110 throw new IllegalArgumentException("Taxon can not be made synonym of its own.");
111 }
112
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 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;
141
142 //the synonyms of the homotypical group of the old taxon
143 if (synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
144 synonymsInHomotypicalGroup = oldTaxon.getSynonymsInGroup(group);
145 }
146
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();
155 } else{
156 srt = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
157 }
158 } else {
159 srt = synRelation.getType();
160
161 }
162
163 newAcceptedTaxon.addSynonym(synRelation.getSynonym(),
164 srt,
165 synRelation.getCitation(),
166 synRelation.getCitationMicroReference());
167
168 /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF())){
169 homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
170 }*/
171
172 }
173
174
175
176
177
178 // CHILD NODES
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()
182 }
183 }
184
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());
193
194 }else if(toTaxon == oldTaxon){
195 fromTaxon.addTaxonRelation(newAcceptedTaxon, taxonRelationship.getType(),
196 taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
197 taxonService.saveOrUpdate(fromTaxon);
198
199 }else{
200 logger.warn("Taxon is not part of its own Taxonrelationship");
201 }
202 // Remove old relationships
203
204 fromTaxon.removeTaxonRelation(taxonRelationship);
205 toTaxon.removeTaxonRelation(taxonRelationship);
206 taxonRelationship.setToTaxon(null);
207 taxonRelationship.setFromTaxon(null);
208 }
209
210
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);
218 }
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);
227 }else{
228 TaxonNodeDeletionConfigurator config = new TaxonNodeDeletionConfigurator();
229 config.setDeleteTaxon(false);
230 conf.setTaxonNodeConfig(config);
231 deleteTaxonNode(oldTaxonNode, conf);
232 }
233
234 //oldTaxonNode.delete();
235 return synonmyRelationship.getSynonym();
236 }
237
238 /* (non-Javadoc)
239 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNodes(java.util.List)
240 */
241 @Override
242 @Transactional(readOnly = false)
243 public List<UUID> deleteTaxonNodes(Set<ITaxonTreeNode> nodes, TaxonDeletionConfigurator config) {
244 if (config == null){
245 config = new TaxonDeletionConfigurator();
246 }
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){
252 TaxonNode taxonNode;
253 taxonNode = HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);
254
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;
262 if (childHandling){
263 boolean changeDeleteTaxon = false;
264 if (!config.getTaxonNodeConfig().isDeleteTaxon()){
265 config.getTaxonNodeConfig().setDeleteTaxon(true);
266 changeDeleteTaxon = true;
267 }
268 deleteTaxonNodes(children, config);
269 if (changeDeleteTaxon){
270 config.getTaxonNodeConfig().setDeleteTaxon(false);
271 }
272
273 } else {
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());
278 }
279
280 }
281 }
282
283 classification = taxonNode.getClassification();
284
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);
291 //node is rootNode
292 if (taxon != null){
293
294 if (config.getTaxonNodeConfig().isDeleteTaxon()){
295 TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
296 configNew.setDeleteTaxonNodes(false);
297 taxonService.deleteTaxon(taxon, configNew, classification);
298 }
299 }
300 classification = null;
301
302 }else {
303 classification = null;
304 Taxon taxon = taxonNode.getTaxon();
305 //node is rootNode
306 if (taxon != null){
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);
312 }
313 }
314
315 }
316
317 UUID uuid = dao.delete(taxonNode);
318 logger.debug("Deleted node " +uuid.toString());
319 }else {
320 classification = (Classification) treeNode;
321
322 }
323
324 deletedUUIDs.add(treeNode.getUuid());
325
326 }
327 }
328 if (classification != null){
329 classService.delete(classification);
330 }
331 return deletedUUIDs;
332
333 }
334 /* (non-Javadoc)
335 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNode(java.util.List)
336 */
337 @Override
338 @Transactional(readOnly = false)
339 public String deleteTaxonNode(TaxonNode node, TaxonDeletionConfigurator config) {
340 Taxon taxon = (Taxon)HibernateProxyHelper.deproxy(node.getTaxon());
341 if (config == null){
342 config = new TaxonDeletionConfigurator();
343 }
344 if (config.getTaxonNodeConfig().isDeleteTaxon()){
345 return taxonService.deleteTaxon(taxon, config, node.getClassification());
346 } else{
347 taxon.removeTaxonNode(node);
348 dao.delete(node);
349 return node.getUuid().toString();
350 }
351
352 }
353
354 /* (non-Javadoc)
355 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#listAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification, int, int)
356 */
357 @Override
358 public List<TaxonNode> listAllNodesForClassification(Classification classification, Integer start, Integer end) {
359 return dao.getTaxonOfAcceptedTaxaByClassification(classification, start, end);
360 }
361
362 /* (non-Javadoc)
363 * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#countAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification)
364 */
365 @Override
366 public int countAllNodesForClassification(Classification classification) {
367 return dao.countTaxonOfAcceptedTaxaByClassification(classification);
368 }
369
370
371
372 }