Project

General

Profile

Download (19.3 KB) Statistics
| Branch: | Tag: | Revision:
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.Collection;
15
import java.util.Collections;
16
import java.util.Comparator;
17
import java.util.HashSet;
18
import java.util.List;
19
import java.util.Set;
20
import java.util.UUID;
21

    
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.annotation.Transactional;
26

    
27
import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
28
import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator;
29
import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator.ChildHandling;
30
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
31
import eu.etaxonomy.cdm.model.description.TaxonDescription;
32
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
33
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
34
import eu.etaxonomy.cdm.model.reference.Reference;
35
import eu.etaxonomy.cdm.model.taxon.Classification;
36
import eu.etaxonomy.cdm.model.taxon.ITaxonNodeComparator;
37
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
38
import eu.etaxonomy.cdm.model.taxon.Synonym;
39
import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
40
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
41
import eu.etaxonomy.cdm.model.taxon.Taxon;
42
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
43
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
44
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
45
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
46

    
47
/**
48
 * @author n.hoffmann
49
 * @created Apr 9, 2010
50
 * @version 1.0
51
 */
52
@Service
53
@Transactional(readOnly = true)
54
public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITaxonNodeDao> implements ITaxonNodeService{
55
    private static final Logger logger = Logger.getLogger(TaxonNodeServiceImpl.class);
56

    
57
    @Autowired
58
    private IBeanInitializer defaultBeanInitializer;
59

    
60
    private Comparator<? super TaxonNode> taxonNodeComparator;
61

    
62
    @Autowired
63
    private ITaxonService taxonService;
64

    
65
    @Autowired
66
    private IClassificationService classService;
67

    
68
    @Autowired
69
    public void setTaxonNodeComparator(ITaxonNodeComparator<? super TaxonNode> taxonNodeComparator){
70
        this.taxonNodeComparator = (Comparator<? super TaxonNode>) taxonNodeComparator;
71
    }
72

    
73
    @Override
74
    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
75
            List<String> propertyPaths, boolean recursive, boolean sorted) {
76
        taxonNode = dao.load(taxonNode.getUuid());
77
        List<TaxonNode> childNodes;
78
        if (recursive == true){
79
        	childNodes  = dao.listChildrenOf(taxonNode, null, null, null, recursive);
80
        }else{
81
        	childNodes = new ArrayList<TaxonNode>(taxonNode.getChildNodes());
82
        }
83
        if (sorted){
84
        	Collections.sort(childNodes, taxonNodeComparator);
85
        }
86
        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
87
        return childNodes;
88
    }
89

    
90
    /* (non-Javadoc)
91
     * @see eu.etaxonomy.cdm.api.service.ServiceBase#setDao(eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao)
92
     */
93
    @Override
94
    @Autowired
95
    protected void setDao(ITaxonNodeDao dao) {
96
        this.dao = dao;
97
    }
98

    
99
    /* (non-Javadoc)
100
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#makeTaxonSynonym(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Taxon)
101
     */
102
    @Override
103
    @Transactional(readOnly = false)
104
    public Synonym makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode,
105
            TaxonNode newAcceptedTaxonNode,
106
            SynonymRelationshipType synonymRelationshipType,
107
            Reference citation,
108
            String citationMicroReference)  {
109

    
110
        // TODO at the moment this method only moves synonym-, concept relations and descriptions to the new accepted taxon
111
        // in a future version we also want to move cdm data like annotations, marker, so., but we will need a policy for that
112
        if (oldTaxonNode == null || newAcceptedTaxonNode == null || oldTaxonNode.getTaxon().getName() == null){
113
            throw new IllegalArgumentException("A mandatory parameter was null.");
114
        }
115

    
116
        if(oldTaxonNode.equals(newAcceptedTaxonNode)){
117
            throw new IllegalArgumentException("Taxon can not be made synonym of its own.");
118
        }
119

    
120

    
121

    
122
        Taxon oldTaxon = (Taxon) HibernateProxyHelper.deproxy(oldTaxonNode.getTaxon());
123
        Taxon newAcceptedTaxon = (Taxon)this.taxonService.load(newAcceptedTaxonNode.getTaxon().getUuid());
124
        // Move oldTaxon to newTaxon
125
        //TaxonNameBase<?,?> synonymName = oldTaxon.getName();
126
        TaxonNameBase<?,?> synonymName = (TaxonNameBase)HibernateProxyHelper.deproxy(oldTaxon.getName());
127
        HomotypicalGroup group = synonymName.getHomotypicalGroup();
128
        if (synonymRelationshipType == null){
129
            if (synonymName.isHomotypic(newAcceptedTaxon.getName())){
130
                synonymRelationshipType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
131
            }else{
132
                synonymRelationshipType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
133
            }
134
        }
135

    
136
        //set homotypic group
137
        HomotypicalGroup newAcceptedTaxonHomotypicalgroup = newAcceptedTaxon.getHomotypicGroup();
138
       HibernateProxyHelper.deproxy(newAcceptedTaxonHomotypicalgroup);
139
       HibernateProxyHelper.deproxy(newAcceptedTaxon.getName());
140
        // Move Synonym Relations to new Taxon
141
        SynonymRelationship synonmyRelationship = newAcceptedTaxon.addSynonymName(synonymName,
142
                synonymRelationshipType, citation, citationMicroReference);
143
         HomotypicalGroup homotypicalGroupAcceptedTaxon = synonmyRelationship.getSynonym().getHomotypicGroup();
144
        // Move Synonym Relations to new Taxon
145
        // From ticket 3163 we can move taxon with accepted name having homotypic synonyms
146
        List<Synonym> synonymsInHomotypicalGroup = null;
147

    
148
        //the synonyms of the homotypical group of the old taxon
149
        if (synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
150
        	synonymsInHomotypicalGroup = oldTaxon.getSynonymsInGroup(group);
151
        }
152

    
153
        for(SynonymRelationship synRelation : oldTaxon.getSynonymRelations()){
154
            SynonymRelationshipType srt;
155
            if(synRelation.getSynonym().getName().getHomotypicalGroup()!= null
156
                    && synRelation.getSynonym().getName().getHomotypicalGroup().equals(newAcceptedTaxon.getName().getHomotypicalGroup())) {
157
                srt = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
158
            } else if(synRelation.getType() != null && synRelation.getType().equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())) {
159
            	if (synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
160
            		srt = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
161
            	} else{
162
            		srt = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
163
            	}
164
            } else {
165
                srt = synRelation.getType();
166

    
167
            }
168

    
169
            newAcceptedTaxon.addSynonym(synRelation.getSynonym(),
170
                    srt,
171
                    synRelation.getCitation(),
172
                    synRelation.getCitationMicroReference());
173

    
174
            /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF())){
175
            	homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
176
            }*/
177

    
178
        }
179

    
180

    
181

    
182

    
183

    
184
        // CHILD NODES
185
        if(oldTaxonNode.getChildNodes() != null && oldTaxonNode.getChildNodes().size() != 0){
186
            for(TaxonNode childNode : oldTaxonNode.getChildNodes()){
187
                newAcceptedTaxonNode.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference()); // childNode.getSynonymToBeUsed()
188
            }
189
        }
190

    
191
        //Move Taxon RelationShips to new Taxon
192
        Set<TaxonRelationship> obsoleteTaxonRelationships = new HashSet<TaxonRelationship>();
193
        for(TaxonRelationship taxonRelationship : oldTaxon.getTaxonRelations()){
194
            Taxon fromTaxon = (Taxon) HibernateProxyHelper.deproxy(taxonRelationship.getFromTaxon());
195
            Taxon toTaxon = (Taxon) HibernateProxyHelper.deproxy(taxonRelationship.getToTaxon());
196
            if (fromTaxon == oldTaxon){
197
                newAcceptedTaxon.addTaxonRelation(taxonRelationship.getToTaxon(), taxonRelationship.getType(),
198
                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
199

    
200
            }else if(toTaxon == oldTaxon){
201
               fromTaxon.addTaxonRelation(newAcceptedTaxon, taxonRelationship.getType(),
202
                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
203
               taxonService.saveOrUpdate(fromTaxon);
204

    
205
            }else{
206
                logger.warn("Taxon is not part of its own Taxonrelationship");
207
            }
208
            // Remove old relationships
209

    
210
            fromTaxon.removeTaxonRelation(taxonRelationship);
211
            toTaxon.removeTaxonRelation(taxonRelationship);
212
            taxonRelationship.setToTaxon(null);
213
            taxonRelationship.setFromTaxon(null);
214
        }
215

    
216

    
217
        //Move descriptions to new taxon
218
        List<TaxonDescription> descriptions = new ArrayList<TaxonDescription>( oldTaxon.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())
219
        for(TaxonDescription description : descriptions){
220
            String message = "Description copied from former accepted taxon: %s (Old title: %s)";
221
            message = String.format(message, oldTaxon.getTitleCache(), description.getTitleCache());
222
            description.setTitleCache(message, true);
223
            //oldTaxon.removeDescription(description, false);
224
            newAcceptedTaxon.addDescription(description);
225
        }
226
        oldTaxon.clearDescriptions();
227

    
228
        taxonService.update(newAcceptedTaxon);
229
        TaxonDeletionConfigurator conf = new TaxonDeletionConfigurator();
230
        conf.setDeleteSynonymsIfPossible(false);
231
        DeleteResult result = taxonService.isDeletable(oldTaxon, conf);
232
//        conf.setDeleteNameIfPossible(false);
233

    
234
        if (result.isOk()){
235
        	 result = taxonService.deleteTaxon(oldTaxon, conf, null);
236
        }else{
237
        	TaxonNodeDeletionConfigurator config = new TaxonNodeDeletionConfigurator();
238
        	config.setDeleteTaxon(false);
239
        	conf.setTaxonNodeConfig(config);
240
        	result = deleteTaxonNode(oldTaxonNode, conf);
241
        }
242

    
243
        //oldTaxonNode.delete();
244
        return synonmyRelationship.getSynonym();
245
    }
246

    
247

    
248
    /* (non-Javadoc)
249
     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#makeTaxonNodeASynonymOfAnotherTaxonNode(java.util.UUID, java.util.UUID, java.util.UUID, java.util.UUID, java.lang.String)
250
     */
251
    @Override
252
    @Transactional(readOnly = false)
253
    public Synonym makeTaxonNodeASynonymOfAnotherTaxonNode(UUID oldTaxonNodeUuid,
254
            UUID newAcceptedTaxonNodeUUID,
255
            SynonymRelationshipType synonymRelationshipType,
256
            Reference citation,
257
            String citationMicroReference) {
258

    
259
        return makeTaxonNodeASynonymOfAnotherTaxonNode(dao.load(oldTaxonNodeUuid),
260
                dao.load(newAcceptedTaxonNodeUUID),
261
                synonymRelationshipType,
262
                citation,
263
                citationMicroReference);
264
    }
265

    
266
    /* (non-Javadoc)
267
     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNodes(java.util.List)
268
     */
269
    @Override
270
    @Transactional(readOnly = false)
271
    public DeleteResult deleteTaxonNodes(Set<ITaxonTreeNode> nodes, TaxonDeletionConfigurator config) {
272

    
273
        if (config == null){
274
        	config = new TaxonDeletionConfigurator();
275
        }
276
        DeleteResult result = new DeleteResult();
277
        List<UUID> deletedUUIDs = new ArrayList<UUID>();
278
        Classification classification = null;
279
        for (ITaxonTreeNode treeNode:nodes){
280
        	if (treeNode != null){
281
	        	if (treeNode instanceof TaxonNode){
282
	        		TaxonNode taxonNode;
283
		            taxonNode = HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);
284

    
285
		            	//check whether the node has children or the children are already deleted
286
		            if(taxonNode.hasChildNodes()){
287
	            		Set<ITaxonTreeNode> children = new HashSet<ITaxonTreeNode> ();
288
	            		List<TaxonNode> childNodesList = taxonNode.getChildNodes();
289
	        			children.addAll(childNodesList);
290
	        			int compare = config.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling.DELETE);
291
	        			boolean childHandling = (compare == 0)? true: false;
292
	            		if (childHandling){
293
	            			boolean changeDeleteTaxon = false;
294
	            			if (!config.getTaxonNodeConfig().isDeleteTaxon()){
295
	            				config.getTaxonNodeConfig().setDeleteTaxon(true);
296
	            				changeDeleteTaxon = true;
297
	            			}
298
	            			DeleteResult resultNodes = deleteTaxonNodes(children, config);
299
	            			if (!resultNodes.isOk()){
300
                                result.addExceptions(resultNodes.getExceptions());
301
                                result.setStatus(resultNodes.getStatus());
302
                            }
303
	            			if (changeDeleteTaxon){
304
	            				config.getTaxonNodeConfig().setDeleteTaxon(false);
305
	            			}
306

    
307
	            		} else {
308
	            			//move the children to the parent
309
	            			TaxonNode parent = taxonNode.getParent();
310
	            			for (TaxonNode child: childNodesList){
311
	            				parent.addChildNode(child, child.getReference(), child.getMicroReference());
312
	            			}
313

    
314
	            		}
315
	            	}
316

    
317
		            classification = taxonNode.getClassification();
318

    
319
		            if (classification.getRootNode().equals(taxonNode)){
320
		            	classification.removeRootNode();
321
		            	classification = null;
322
		            }else if (classification.getChildNodes().contains(taxonNode)){
323
	            		Taxon taxon = taxonNode.getTaxon();
324
	            		classification.deleteChildNode(taxonNode);
325

    
326
		            	//node is rootNode
327
		            	if (taxon != null){
328

    
329
		            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
330
		            		    taxonService.saveOrUpdate(taxon);
331
		            		    saveOrUpdate(taxonNode);
332
				            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
333
				            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon, configNew, classification);
334
				            	if (!resultTaxon.isOk()){
335
	                                result.addExceptions(resultTaxon.getExceptions());
336
	                                result.setStatus(resultTaxon.getStatus());
337
	                            }
338

    
339
			            	}
340
		            	}
341
	            		classification = null;
342

    
343
		            }else {
344
		            	classification = null;
345
		            	Taxon taxon = taxonNode.getTaxon();
346
		            	//node is rootNode
347
		            	if (taxon != null){
348
		            		taxonNode.getTaxon().removeTaxonNode(taxonNode);
349
		            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
350
				            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
351
				            	saveOrUpdate(taxonNode);
352
				            	taxonService.saveOrUpdate(taxon);
353
				            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon, configNew, classification);
354
                                if (!resultTaxon.isOk()){
355
                                    result.addExceptions(resultTaxon.getExceptions());
356
                                    result.setStatus(resultTaxon.getStatus());
357
                                }
358
			            	}
359
		            	}
360

    
361
		            }
362

    
363
		            UUID uuid = dao.delete(taxonNode);
364
		            logger.debug("Deleted node " +uuid.toString());
365
	        	}else {
366
	        		classification = (Classification) treeNode;
367

    
368
	        	}
369

    
370
	            //deletedUUIDs.add(treeNode.getUuid());
371

    
372
	        }
373
        }
374
        if (classification != null){
375
        	DeleteResult resultClassification = classService.delete(classification);
376
        	 if (!resultClassification.isOk()){
377
                 result.addExceptions(resultClassification.getExceptions());
378
                 result.setStatus(resultClassification.getStatus());
379
             }
380
        }
381
        return result;
382

    
383
    }
384

    
385
    @Override
386
    @Transactional(readOnly = false)
387
    public DeleteResult deleteTaxonNodes(Collection<UUID> nodeUuids, TaxonDeletionConfigurator config) {
388
        Set<ITaxonTreeNode> nodes = new HashSet<ITaxonTreeNode>();
389
        for(UUID nodeUuid : nodeUuids) {
390
            nodes.add(dao.load(nodeUuid));
391
        }
392
        return deleteTaxonNodes(nodes, config);
393
    }
394

    
395
    /* (non-Javadoc)
396
     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNode(java.util.List)
397
     */
398
    @Override
399
    @Transactional(readOnly = false)
400
    public DeleteResult deleteTaxonNode(TaxonNode node, TaxonDeletionConfigurator config) {
401

    
402
    	Taxon taxon = (Taxon)HibernateProxyHelper.deproxy(node.getTaxon());
403
    	if (config == null){
404
    		config = new TaxonDeletionConfigurator();
405
    	}
406
    	if (config.getTaxonNodeConfig().isDeleteTaxon()){
407
    		return taxonService.deleteTaxon(taxon, config, node.getClassification());
408
    	} else{
409
    		DeleteResult result = new DeleteResult();
410
    		boolean success = taxon.removeTaxonNode(node);
411
    		if (success){
412
    			if (!dao.delete(node).equals(null)){
413
    				return result;
414
    			} else {
415
    				result.setError();
416
    				return result;
417
    			}
418
    		}else{
419
    			result.setError();
420
    			result.addException(new Exception("The node can not be removed from the taxon."));
421
    			return result;
422
    		}
423

    
424
    	}
425

    
426
    }
427

    
428

    
429
    @Override
430
    @Transactional(readOnly = false)
431
    public DeleteResult deleteTaxonNode(UUID nodeUuid, TaxonDeletionConfigurator config) {
432
        DeleteResult dr = deleteTaxonNode(dao.load(nodeUuid), config);
433
        return dr;
434
    }
435

    
436

    
437
    @Override
438
    @Transactional(readOnly = false)
439
    public TaxonNode moveTaxonNode(TaxonNode taxonNode, TaxonNode newParentTaxonNode) {
440
        return newParentTaxonNode.addChildNode(taxonNode,
441
                newParentTaxonNode.getReference(),
442
                newParentTaxonNode.getMicroReference());
443

    
444
    }
445

    
446
    @Override
447
    @Transactional(readOnly = false)
448
    public TaxonNode moveTaxonNode(UUID taxonNodeUuid, UUID newParentTaxonNodeUuid) {
449
        return moveTaxonNode(dao.load(taxonNodeUuid), dao.load(newParentTaxonNodeUuid));
450

    
451
    }
452

    
453
    /* (non-Javadoc)
454
     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#listAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification, int, int)
455
     */
456
    @Override
457
    public List<TaxonNode> listAllNodesForClassification(Classification classification, Integer start, Integer end) {
458
        return dao.getTaxonOfAcceptedTaxaByClassification(classification, start, end);
459
    }
460

    
461
    /* (non-Javadoc)
462
     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#countAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification)
463
     */
464
    @Override
465
    public int countAllNodesForClassification(Classification classification) {
466
        return dao.countTaxonOfAcceptedTaxaByClassification(classification);
467
    }
468

    
469

    
470

    
471

    
472
}
(82-82/88)