Project

General

Profile

Download (43.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.api.service;
11

    
12
import java.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.Comparator;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.Map.Entry;
21
import java.util.Set;
22
import java.util.UUID;
23

    
24
import org.apache.log4j.Logger;
25
import org.springframework.beans.factory.annotation.Autowired;
26
import org.springframework.stereotype.Service;
27
import org.springframework.transaction.annotation.Transactional;
28
import org.springframework.transaction.interceptor.TransactionAspectSupport;
29

    
30
import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
31
import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;
32
import eu.etaxonomy.cdm.api.service.config.SecundumForSubtreeConfigurator;
33
import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
34
import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator;
35
import eu.etaxonomy.cdm.api.service.dto.CdmEntityIdentifier;
36
import eu.etaxonomy.cdm.api.service.dto.TaxonDistributionDTO;
37
import eu.etaxonomy.cdm.api.service.pager.Pager;
38
import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
39
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
40
import eu.etaxonomy.cdm.common.monitor.DefaultProgressMonitor;
41
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
42
import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
43
import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
44
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
45
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
46
import eu.etaxonomy.cdm.model.common.CdmBase;
47
import eu.etaxonomy.cdm.model.common.DefinedTerm;
48
import eu.etaxonomy.cdm.model.common.Language;
49
import eu.etaxonomy.cdm.model.common.LanguageString;
50
import eu.etaxonomy.cdm.model.common.TreeIndex;
51
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
52
import eu.etaxonomy.cdm.model.description.TaxonDescription;
53
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
54
import eu.etaxonomy.cdm.model.name.HybridRelationship;
55
import eu.etaxonomy.cdm.model.name.TaxonName;
56
import eu.etaxonomy.cdm.model.reference.Reference;
57
import eu.etaxonomy.cdm.model.taxon.Classification;
58
import eu.etaxonomy.cdm.model.taxon.HomotypicGroupTaxonComparator;
59
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
60
import eu.etaxonomy.cdm.model.taxon.Synonym;
61
import eu.etaxonomy.cdm.model.taxon.SynonymType;
62
import eu.etaxonomy.cdm.model.taxon.Taxon;
63
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
64
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
65
import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
66
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
67
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
68
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
69
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeFilterDao;
70
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
71
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
72

    
73
/**
74
 * @author n.hoffmann
75
 * @since Apr 9, 2010
76
 */
77
@Service
78
@Transactional(readOnly = true)
79
public class TaxonNodeServiceImpl
80
           extends AnnotatableServiceBase<TaxonNode, ITaxonNodeDao>
81
           implements ITaxonNodeService{
82
    private static final Logger logger = Logger.getLogger(TaxonNodeServiceImpl.class);
83

    
84
    @Autowired
85
    private IBeanInitializer defaultBeanInitializer;
86

    
87
    @Autowired
88
    private ITaxonService taxonService;
89

    
90
    @Autowired
91
    private IDescriptiveDataSetService dataSetService;
92

    
93
    @Autowired
94
    private IAgentService agentService;
95

    
96
    @Autowired
97
    private INameService nameService;
98

    
99
    @Autowired
100
    private IReferenceService refService;
101

    
102
    @Autowired
103
    private ITaxonNodeFilterDao nodeFilterDao;
104

    
105
    @Autowired
106
    IProgressMonitorService progressMonitorService;
107

    
108

    
109
    @Override
110
    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
111
            List<String> propertyPaths, boolean recursive,  boolean includeUnpublished,
112
            NodeSortMode sortMode) {
113

    
114
        getSession().refresh(taxonNode);
115
        List<TaxonNode> childNodes;
116
        if (recursive == true){
117
        	childNodes  = dao.listChildrenOf(taxonNode, null, null, recursive, includeUnpublished, null);
118
        }else if (includeUnpublished){
119
            childNodes = new ArrayList<>(taxonNode.getChildNodes());
120
        }else{
121
            childNodes = new ArrayList<>();
122
            for (TaxonNode node:taxonNode.getChildNodes()){
123
                if (node.getTaxon().isPublish()){
124
                    childNodes.add(node);
125
                }
126
            }
127
        }
128

    
129
        HHH_9751_Util.removeAllNull(childNodes);
130

    
131
        if (sortMode != null){
132
            Comparator<TaxonNode> comparator = sortMode.newComparator();
133
        	Collections.sort(childNodes, comparator);
134
        }
135
        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
136
        return childNodes;
137
    }
138

    
139
    @Override
140
    public List<TaxonNode> listChildrenOf(TaxonNode node, Integer pageSize, Integer pageIndex,
141
            boolean recursive, boolean includeUnpublished, List<String> propertyPaths){
142
        return dao.listChildrenOf(node, pageSize, pageIndex, recursive, includeUnpublished, propertyPaths);
143
    }
144

    
145
    /**
146
     * {@inheritDoc}
147
     */
148
    @Override
149
    public UuidAndTitleCache<TaxonNode> getParentUuidAndTitleCache(ITaxonTreeNode child) {
150
        UUID uuid = child.getUuid();
151
        int id = child.getId();
152
        UuidAndTitleCache<TaxonNode> uuidAndTitleCache = new UuidAndTitleCache<>(uuid, id, null);
153
        return getParentUuidAndTitleCache(uuidAndTitleCache);
154
    }
155

    
156
    /**
157
     * {@inheritDoc}
158
     */
159
    @Override
160
    public UuidAndTitleCache<TaxonNode> getParentUuidAndTitleCache(UuidAndTitleCache<TaxonNode> child) {
161
        return dao.getParentUuidAndTitleCache(child);
162
    }
163

    
164
    /**
165
     * {@inheritDoc}
166
     */
167
    @Override
168
    public List<TaxonNodeDto> listChildNodesAsTaxonNodeDto(UuidAndTitleCache<TaxonNode> parent) {
169
        return dao.listChildNodesAsTaxonNodeDto(parent);
170
    }
171

    
172
    /**
173
     * {@inheritDoc}
174
     */
175
    @Override
176
    public List<UuidAndTitleCache<TaxonNode>> listChildNodesAsUuidAndTitleCache(UuidAndTitleCache<TaxonNode> parent) {
177
        return dao.listChildNodesAsUuidAndTitleCache(parent);
178
    }
179

    
180

    
181
    /**
182
     * {@inheritDoc}
183
     */
184
    @Override
185
    public List<UuidAndTitleCache<TaxonNode>> getUuidAndTitleCache(Integer limit, String pattern, UUID classificationUuid) {
186
        return dao.getUuidAndTitleCache(limit, pattern, classificationUuid);
187
    }
188

    
189
    /**
190
     * {@inheritDoc}
191
     */
192
    @Override
193
    public List<TaxonNodeDto> listChildNodesAsTaxonNodeDto(ITaxonTreeNode parent) {
194
        UUID uuid = parent.getUuid();
195
        int id = parent.getId();
196
        UuidAndTitleCache<TaxonNode> uuidAndTitleCache = new UuidAndTitleCache<>(uuid, id, null);
197
        return listChildNodesAsTaxonNodeDto(uuidAndTitleCache);
198
    }
199

    
200
    @Override
201
    public List<UuidAndTitleCache<TaxonNode>> listChildNodesAsUuidAndTitleCache(ITaxonTreeNode parent) {
202
        UUID uuid = parent.getUuid();
203
        int id = parent.getId();
204
        UuidAndTitleCache<TaxonNode> uuidAndTitleCache = new UuidAndTitleCache<>(uuid, id, null);
205
        return listChildNodesAsUuidAndTitleCache(uuidAndTitleCache);
206
    }
207

    
208
    /**
209
     * {@inheritDoc}
210
     */
211
    @Override
212
    public Pager<TaxonNodeDto> pageChildNodesDTOs(UUID taxonNodeUuid, boolean recursive,  boolean includeUnpublished,
213
            boolean doSynonyms, NodeSortMode sortMode,
214
            Integer pageSize, Integer pageIndex) {
215

    
216
        TaxonNode parentNode = dao.load(taxonNodeUuid);
217

    
218
        List<CdmBase> allRecords = new ArrayList<>();
219

    
220
        //acceptedTaxa
221
        List<TaxonNode> childNodes = loadChildNodesOfTaxonNode(parentNode, null, recursive, includeUnpublished, sortMode);
222
        allRecords.addAll(childNodes);
223

    
224
        //add synonyms if pager is not yet full synonyms
225
        if (doSynonyms){
226
            List<Synonym> synList = new ArrayList<>(parentNode.getTaxon().getSynonyms());
227
            Collections.sort(synList, new HomotypicGroupTaxonComparator(null));
228
            //TODO: test sorting
229

    
230
            allRecords.addAll(synList);
231
        }
232

    
233
        List<TaxonNodeDto> dtos = new ArrayList<>(pageSize==null?25:pageSize);
234
        long totalCount = Long.valueOf(allRecords.size());
235

    
236
        TaxonName parentName = null;
237

    
238
        for(CdmBase record : PagerUtils.pageList(allRecords, pageIndex, pageSize)) {
239
            if (record.isInstanceOf(TaxonNode.class)){
240
                dtos.add(new TaxonNodeDto(CdmBase.deproxy(record, TaxonNode.class)));
241
            }else if (record.isInstanceOf(Synonym.class)){
242
                Synonym synonym = CdmBase.deproxy(record, Synonym.class);
243
                parentName = parentName == null? parentNode.getTaxon().getName(): parentName;
244
                boolean isHomotypic = synonym.getName().isHomotypic(parentName);
245
                dtos.add(new TaxonNodeDto(synonym, isHomotypic));
246
            }
247
        }
248
        return new DefaultPagerImpl<>(pageIndex, totalCount, pageSize , dtos);
249
    }
250

    
251
    @Override
252
    public TaxonNodeDto parentDto(UUID taxonNodeUuid) {
253
        TaxonNode taxonNode = dao.load(taxonNodeUuid);
254
        if(taxonNode.getParent() != null) {
255
            return new TaxonNodeDto(taxonNode.getParent());
256
        }
257
        return null;
258
    }
259

    
260
    @Override
261
    public TaxonNodeDto dto(UUID taxonNodeUuid) {
262
        TaxonNode taxonNode = dao.load(taxonNodeUuid);
263
        if(taxonNode.getParent() != null) {
264
            return new TaxonNodeDto(taxonNode);
265
        }
266
        return null;
267
    }
268

    
269
    @Override
270
    @Autowired
271
    protected void setDao(ITaxonNodeDao dao) {
272
        this.dao = dao;
273
    }
274

    
275
    @Override
276
    @Transactional(readOnly = false)
277
    public DeleteResult makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode,
278
            SynonymType synonymType, Reference citation, String citationMicroReference)  {
279

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

    
286
        if(oldTaxonNode.equals(newAcceptedTaxonNode)){
287
            throw new IllegalArgumentException("Taxon can not be made synonym of its own.");
288
        }
289

    
290
        Classification classification = oldTaxonNode.getClassification();
291
        Taxon oldTaxon = HibernateProxyHelper.deproxy(oldTaxonNode.getTaxon());
292
        Taxon newAcceptedTaxon = (Taxon)this.taxonService.find(newAcceptedTaxonNode.getTaxon().getUuid());
293
        newAcceptedTaxon = HibernateProxyHelper.deproxy(newAcceptedTaxon);
294
        // Move oldTaxon to newTaxon
295
        //TaxonName synonymName = oldTaxon.getName();
296
        TaxonName newSynonymName = CdmBase.deproxy(oldTaxon.getName());
297
        HomotypicalGroup group = CdmBase.deproxy(newSynonymName.getHomotypicalGroup());
298
        if (synonymType == null){
299
            if (newSynonymName.isHomotypic(newAcceptedTaxon.getName())){
300
                synonymType = SynonymType.HOMOTYPIC_SYNONYM_OF();
301
            }else{
302
                synonymType = SynonymType.HETEROTYPIC_SYNONYM_OF();
303
            }
304
        }
305

    
306
        //set homotypic group
307
        TaxonName newAcceptedTaxonName = HibernateProxyHelper.deproxy(newAcceptedTaxon.getName(), TaxonName.class);
308
        newAcceptedTaxon.setName(newAcceptedTaxonName);
309
        // Move Synonym Relations to new Taxon
310
        newAcceptedTaxon.addSynonymName(newSynonymName, citation, citationMicroReference, synonymType);
311
         // Move Synonyms to new Taxon
312
        // From ticket 3163 we can move taxon with accepted name having homotypic synonyms
313
        List<Synonym> synonymsInHomotypicalGroup = null;
314

    
315
        //the synonyms of the homotypical group of the old taxon
316
        if (synonymType.equals(SynonymType.HOMOTYPIC_SYNONYM_OF())){
317
        	synonymsInHomotypicalGroup = oldTaxon.getSynonymsInGroup(group);
318
        }
319

    
320
        Set<Synonym> syns = new HashSet<>(oldTaxon.getSynonyms());
321
        for(Synonym synonym : syns){
322
            SynonymType srt;
323
            if(synonym.getHomotypicGroup()!= null
324
                    && synonym.getHomotypicGroup().equals(newAcceptedTaxonName.getHomotypicalGroup())) {
325
                srt = SynonymType.HOMOTYPIC_SYNONYM_OF();
326
            } else if(synonym.getType() != null && synonym.getType().equals(SynonymType.HOMOTYPIC_SYNONYM_OF())) {
327
            	if (synonymType.equals(SynonymType.HOMOTYPIC_SYNONYM_OF())){
328
            		srt = SynonymType.HOMOTYPIC_SYNONYM_OF();
329
            	} else{
330
            		srt = SynonymType.HETEROTYPIC_SYNONYM_OF();
331
            	}
332
            } else {
333
                if (synonymsInHomotypicalGroup != null && synonymsInHomotypicalGroup.contains(synonym)){
334
                    srt = SynonymType.HOMOTYPIC_SYNONYM_OF();
335
                }else{
336
                    srt = synonym.getType();
337
                }
338

    
339
            }
340

    
341
            newAcceptedTaxon.addSynonym(synonym, srt);
342

    
343

    
344
            /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymType.HETEROTYPIC_SYNONYM_OF())){
345
            	homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
346
            }*/
347

    
348
        }
349

    
350

    
351
        // CHILD NODES
352
        if(oldTaxonNode.getChildNodes() != null && oldTaxonNode.getChildNodes().size() != 0){
353
        	List<TaxonNode> childNodes = new ArrayList<>();
354
        	for (TaxonNode childNode : oldTaxonNode.getChildNodes()){
355
        		childNodes.add(childNode);
356
        	}
357
            for(TaxonNode childNode :childNodes){
358
                newAcceptedTaxonNode.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference()); // childNode.getSynonymToBeUsed()
359
            }
360
        }
361

    
362
        //Move Taxon RelationShips to new Taxon
363
        for(TaxonRelationship taxonRelationship : oldTaxon.getTaxonRelations()){
364
            Taxon fromTaxon = HibernateProxyHelper.deproxy(taxonRelationship.getFromTaxon());
365
            Taxon toTaxon = HibernateProxyHelper.deproxy(taxonRelationship.getToTaxon());
366
            if (fromTaxon == oldTaxon){
367
                newAcceptedTaxon.addTaxonRelation(taxonRelationship.getToTaxon(), taxonRelationship.getType(),
368
                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
369

    
370
            }else if(toTaxon == oldTaxon){
371
               fromTaxon.addTaxonRelation(newAcceptedTaxon, taxonRelationship.getType(),
372
                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
373
               taxonService.saveOrUpdate(fromTaxon);
374

    
375
            }else{
376
                logger.warn("Taxon is not part of its own Taxonrelationship");
377
            }
378
            // Remove old relationships
379

    
380
            fromTaxon.removeTaxonRelation(taxonRelationship);
381
            toTaxon.removeTaxonRelation(taxonRelationship);
382
            taxonRelationship.setToTaxon(null);
383
            taxonRelationship.setFromTaxon(null);
384
        }
385

    
386

    
387
        //Move descriptions to new taxon
388
        List<TaxonDescription> descriptions = new ArrayList<TaxonDescription>( oldTaxon.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())
389
        for(TaxonDescription description : descriptions){
390
            String message = "Description copied from former accepted taxon: %s (Old title: %s)";
391
            message = String.format(message, oldTaxon.getTitleCache(), description.getTitleCache());
392
            description.setTitleCache(message, true);
393
            //oldTaxon.removeDescription(description, false);
394
            newAcceptedTaxon.addDescription(description);
395
        }
396
        oldTaxon.clearDescriptions();
397

    
398
        taxonService.saveOrUpdate(newAcceptedTaxon);
399

    
400
        taxonService.saveOrUpdate(oldTaxon);
401
        taxonService.getSession().flush();
402

    
403
        TaxonDeletionConfigurator conf = new TaxonDeletionConfigurator();
404
        conf.setDeleteSynonymsIfPossible(false);
405
        conf.setDeleteNameIfPossible(false);
406
        DeleteResult result = taxonService.isDeletable(oldTaxon.getUuid(), conf);
407

    
408

    
409
        if (result.isOk()){
410
        	 result = taxonService.deleteTaxon(oldTaxon.getUuid(), conf, classification.getUuid());
411

    
412
        }else{
413
        	result.setStatus(Status.OK);
414
        	TaxonNodeDeletionConfigurator config = new TaxonNodeDeletionConfigurator();
415
        	config.setDeleteElement(false);
416
        	conf.setTaxonNodeConfig(config);
417
        	result.includeResult(deleteTaxonNode(oldTaxonNode, conf));
418
        }
419

    
420
        result.addUpdatedObject(newAcceptedTaxon);
421

    
422

    
423
        //oldTaxonNode.delete();
424
        return result;
425
    }
426
    @Override
427
    @Transactional(readOnly = false)
428
    public UpdateResult makeTaxonNodeSynonymsOfAnotherTaxonNode( Set<UUID> oldTaxonNodeUuids,
429
            UUID newAcceptedTaxonNodeUUIDs,
430
            SynonymType synonymType,
431
            Reference citation,
432
            String citationMicroReference) {
433
    	UpdateResult result = new UpdateResult();
434
    	for (UUID nodeUuid: oldTaxonNodeUuids) {
435
    		result.includeResult(makeTaxonNodeASynonymOfAnotherTaxonNode(nodeUuid, newAcceptedTaxonNodeUUIDs, synonymType, citation, citationMicroReference));
436
    	}
437
    	return result;
438
    }
439

    
440
    @Override
441
    @Transactional(readOnly = false)
442
    public UpdateResult makeTaxonNodeASynonymOfAnotherTaxonNode(UUID oldTaxonNodeUuid,
443
            UUID newAcceptedTaxonNodeUUID,
444
            SynonymType synonymType,
445
            Reference citation,
446
            String citationMicroReference) {
447

    
448
        TaxonNode oldTaxonNode = dao.load(oldTaxonNodeUuid);
449
        TaxonNode oldTaxonParentNode = oldTaxonNode.getParent();
450
        TaxonNode newTaxonNode = dao.load(newAcceptedTaxonNodeUUID);
451

    
452
        UpdateResult result = makeTaxonNodeASynonymOfAnotherTaxonNode(oldTaxonNode,
453
                newTaxonNode,
454
                synonymType,
455
                citation,
456
                citationMicroReference);
457
        result.addUpdatedCdmId(new CdmEntityIdentifier(oldTaxonParentNode.getId(), TaxonNode.class));
458
        result.addUpdatedCdmId(new CdmEntityIdentifier(newTaxonNode.getId(), TaxonNode.class));
459
        result.setCdmEntity(oldTaxonParentNode);
460
        return result;
461
    }
462

    
463
    @Override
464
    @Transactional(readOnly = false)
465
    public DeleteResult deleteTaxonNodes(List<TaxonNode> list, TaxonDeletionConfigurator config) {
466

    
467
        if (config == null){
468
        	config = new TaxonDeletionConfigurator();
469
        }
470
        DeleteResult result = new DeleteResult();
471
        Classification classification = null;
472
        List<TaxonNode> taxonNodes = new ArrayList<>(list);
473

    
474
        for (TaxonNode treeNode:taxonNodes){
475
        	if (treeNode != null){
476

    
477
        		TaxonNode taxonNode;
478
	            taxonNode = HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);
479
	            TaxonNode parent = taxonNode.getParent();
480
	            	//check whether the node has children or the children are already deleted
481
	            if(taxonNode.hasChildNodes()) {
482
            		List<TaxonNode> children = new ArrayList<TaxonNode> ();
483
            		List<TaxonNode> childNodesList = taxonNode.getChildNodes();
484
        			children.addAll(childNodesList);
485
        			//To avoid NPE when child is also in list of taxonNodes, remove it from the list
486
        			Iterator<TaxonNode> it = taxonNodes.iterator();
487
        			for (TaxonNode child: children) {
488
        				while (it.hasNext()) {
489
        					if (it.next().equals(child)) {
490
        						it.remove();
491
        					}
492
        				}
493
        			}
494
        			int compare = config.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling.DELETE);
495
        			boolean childHandling = (compare == 0)? true: false;
496
            		if (childHandling){
497
            			boolean changeDeleteTaxon = false;
498
            			if (!config.getTaxonNodeConfig().isDeleteTaxon()){
499
            				config.getTaxonNodeConfig().setDeleteTaxon(true);
500
            				changeDeleteTaxon = true;
501
            			}
502
            			DeleteResult resultNodes = deleteTaxonNodes(children, config);
503
            			if (!resultNodes.isOk()){
504
                            result.addExceptions(resultNodes.getExceptions());
505
                            result.setStatus(resultNodes.getStatus());
506
                        }
507
            			if (changeDeleteTaxon){
508
            				config.getTaxonNodeConfig().setDeleteTaxon(false);
509
            			}
510

    
511
            		} else {
512
            			//move the children to the parent
513

    
514
            			for (TaxonNode child: childNodesList){
515
            				parent.addChildNode(child, child.getReference(), child.getMicroReference());
516
            			}
517

    
518
            		}
519
            	}
520

    
521
	            classification = taxonNode.getClassification();
522

    
523
	            if (classification.getRootNode().equals(taxonNode)){
524
	            	classification.removeRootNode();
525
	            	classification = null;
526
	            }else if (classification.getChildNodes().contains(taxonNode)){
527
            		Taxon taxon = taxonNode.getTaxon();
528
            		classification.deleteChildNode(taxonNode);
529

    
530
	            	//node is rootNode
531
	            	if (taxon != null){
532

    
533
	            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
534
	            		    taxonService.saveOrUpdate(taxon);
535
	            		    saveOrUpdate(taxonNode);
536

    
537
			            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
538
			            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, classification.getUuid());
539
			            	if (!resultTaxon.isOk()){
540
                                result.addExceptions(resultTaxon.getExceptions());
541
                                result.setStatus(resultTaxon.getStatus());
542
                            }
543

    
544
		            	}
545
	            	}
546
            		classification = null;
547

    
548
	            } else {
549
	            	classification = null;
550
	            	Taxon taxon = taxonNode.getTaxon();
551
	            	taxon = HibernateProxyHelper.deproxy(taxon, Taxon.class);
552
	            	if (taxon != null){
553
	            		taxon.removeTaxonNode(taxonNode);
554
	            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
555
			            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
556
			            	saveOrUpdate(taxonNode);
557
			            	taxonService.saveOrUpdate(taxon);
558
			            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, null);
559

    
560
                            if (!resultTaxon.isOk()){
561
                                result.addExceptions(resultTaxon.getExceptions());
562
                                result.setStatus(resultTaxon.getStatus());
563
                            }
564
		            	}
565
	            	}
566

    
567
	            }
568

    
569
	            result.addUpdatedObject(parent);
570
	            if(result.getCdmEntity() == null){
571
	                result.setCdmEntity(taxonNode);
572
                }
573
	            UUID uuid = dao.delete(taxonNode);
574
	            logger.debug("Deleted node " +uuid.toString());
575

    
576
	        }
577
        }
578
        /*if (classification != null){
579
            result.addUpdatedObject(classification);
580
        	DeleteResult resultClassification = classService.delete(classification);
581
        	 if (!resultClassification.isOk()){
582
                 result.addExceptions(resultClassification.getExceptions());
583
                 result.setStatus(resultClassification.getStatus());
584
             }
585
        }*/
586
        return result;
587
    }
588

    
589

    
590
    @Override
591
    @Transactional(readOnly = false)
592
    public DeleteResult deleteTaxonNodes(Collection<UUID> nodeUuids, TaxonDeletionConfigurator config) {
593
        List<TaxonNode> nodes = new ArrayList<>();
594
        for(UUID nodeUuid : nodeUuids) {
595
            nodes.add(dao.load(nodeUuid));
596
        }
597
        return deleteTaxonNodes(nodes, config);
598
    }
599

    
600

    
601
    @Override
602
    @Transactional(readOnly = false)
603
    public DeleteResult deleteTaxonNode(UUID nodeUUID, TaxonDeletionConfigurator config) {
604

    
605
    	TaxonNode node = HibernateProxyHelper.deproxy(dao.load(nodeUUID), TaxonNode.class);
606
    	return deleteTaxonNode(node, config);
607
    }
608

    
609
    @Override
610
    @Transactional(readOnly = false)
611
    public DeleteResult deleteTaxonNode(TaxonNode node, TaxonDeletionConfigurator config) {
612
        DeleteResult result = new DeleteResult();
613
        if (node == null){
614
            result.setAbort();
615
            result.addException(new Exception("The TaxonNode was already deleted."));
616
            return result;
617
        }
618
        Taxon taxon = null;
619
        try{
620
            taxon = HibernateProxyHelper.deproxy(node.getTaxon());
621
        }catch(NullPointerException e){
622
            result.setAbort();
623
            result.addException(new Exception("The Taxon was already deleted."));
624

    
625
        }
626

    
627

    
628
    	TaxonNode parent = HibernateProxyHelper.deproxy(node.getParent(), TaxonNode.class);
629
    	if (config == null){
630
    		config = new TaxonDeletionConfigurator();
631
    	}
632

    
633

    
634
    	if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.MOVE_TO_PARENT)){
635
    	   Object[] children = node.getChildNodes().toArray();
636
    	   TaxonNode childNode;
637
    	   for (Object child: children){
638
    	       childNode = (TaxonNode) child;
639
    	       parent.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference());
640

    
641
    	   }
642
    	}else{
643
    	    result.includeResult(deleteTaxonNodes(node.getChildNodes(), config));
644
    	}
645

    
646
    	//remove node from DescriptiveDataSet
647
        commonService.getReferencingObjects(node).stream()
648
        .filter(obj->obj instanceof DescriptiveDataSet)
649
        .forEach(dataSet->{
650
            ((DescriptiveDataSet)dataSet).removeTaxonSubtree(node);
651
            dataSetService.saveOrUpdate((DescriptiveDataSet) dataSet);
652
        });
653

    
654
    	if (taxon != null){
655
        	if (config.getTaxonNodeConfig().isDeleteTaxon() && (config.isDeleteInAllClassifications() || taxon.getTaxonNodes().size() == 1)){
656
        		result = taxonService.deleteTaxon(taxon.getUuid(), config, node.getClassification().getUuid());
657
        		result.addUpdatedObject(parent);
658
        		if (result.isOk()){
659
        			return result;
660
        		}
661
        	} else {
662
        	    result.addUpdatedObject(taxon);
663
        	}
664
    	}
665
    	result.setCdmEntity(node);
666
    	boolean success = true;
667
    	if (taxon != null){
668
    	    success = taxon.removeTaxonNode(node);
669
    	    taxonService.saveOrUpdate(taxon);
670
    	}
671
    	dao.saveOrUpdate(parent);
672

    
673
    	result.addUpdatedObject(parent);
674

    
675
    	if (success){
676
			result.setStatus(Status.OK);
677
			if (parent != null){
678
    			parent = HibernateProxyHelper.deproxy(parent, TaxonNode.class);
679
    			int index = parent.getChildNodes().indexOf(node);
680
    			if (index > -1){
681
    			    parent.removeChild(index);
682
    			}
683
			}
684
    		if (!dao.delete(node, config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)).equals(null)){
685
    		    result.getUpdatedObjects().remove(node);
686
    			result.addDeletedObject(node);
687
    			return result;
688
    		} else {
689
    			result.setError();
690
    			return result;
691
    		}
692
    	}else{
693
    	    if (dao.findByUuid(node.getUuid()) != null){
694
        		result.setError();
695
        		result.addException(new Exception("The node can not be removed from the taxon."));
696
    		}
697
    		return result;
698
    	}
699
    }
700

    
701

    
702
    @Override
703
    public List<TaxonNode> listAllNodesForClassification(Classification classification, Integer start, Integer end) {
704
        return dao.getTaxonOfAcceptedTaxaByClassification(classification, start, end);
705
    }
706

    
707
    @Override
708
    public int countAllNodesForClassification(Classification classification) {
709
        return dao.countTaxonOfAcceptedTaxaByClassification(classification);
710
    }
711

    
712
    @Override
713
    @Transactional
714
    public UpdateResult moveTaxonNode(UUID taxonNodeUuid, UUID targetNodeUuid, int movingType){
715
        TaxonNode taxonNode = HibernateProxyHelper.deproxy(dao.load(taxonNodeUuid), TaxonNode.class);
716
    	TaxonNode targetNode = HibernateProxyHelper.deproxy(dao.load(targetNodeUuid), TaxonNode.class);
717
    	UpdateResult result = moveTaxonNode(taxonNode, targetNode, movingType);
718
    	return result;
719
    }
720

    
721
    @Override
722
    @Transactional
723
    public UpdateResult moveTaxonNode(TaxonNode taxonNode, TaxonNode newParent, int movingType){
724
        UpdateResult result = new UpdateResult();
725

    
726
        TaxonNode parentParent = HibernateProxyHelper.deproxy(newParent.getParent());
727
        TaxonNode oldParent = HibernateProxyHelper.deproxy(taxonNode.getParent());
728
        Integer sortIndex = -1;
729
        if (movingType == 0){
730
            sortIndex = 0;
731
        }else if (movingType == 1){
732
            sortIndex = newParent.getSortIndex();
733
            newParent = parentParent;
734
        } else if (movingType == 2){
735
            sortIndex = newParent.getSortIndex() +1;
736
            newParent = parentParent;
737
        } else{
738
            result.setAbort();
739
            result.addException(new Exception("The moving type "+ movingType +" is not supported."));
740
        }
741

    
742
        taxonNode = newParent.addChildNode(taxonNode, sortIndex, taxonNode.getReference(),  taxonNode.getMicroReference());
743
        result.addUpdatedObject(taxonNode);
744

    
745
        return result;
746
    }
747

    
748

    
749

    
750
    @Override
751
    @Transactional
752
    public UpdateResult moveTaxonNodes(Set<UUID> taxonNodeUuids, UUID newParentNodeUuid, int movingType, IProgressMonitor monitor){
753

    
754
        if (monitor == null){
755
            monitor = DefaultProgressMonitor.NewInstance();
756
        }
757
        UpdateResult result = new UpdateResult();
758

    
759
        TaxonNode targetNode = dao.load(newParentNodeUuid);
760
        List<TaxonNode> nodes = dao.list(taxonNodeUuids, null, null, null, null);
761
        boolean hasPermission = true;
762

    
763
        monitor.beginTask("Move Taxonnodes", nodes.size()*2);
764
        monitor.subTask("move taxon nodes");
765
        for (TaxonNode node: nodes){
766
            if (!monitor.isCanceled()){
767
                if (!nodes.contains(node.getParent())){
768
                    result.includeResult(moveTaxonNode(node,targetNode, movingType));
769
                }
770
                monitor.worked(1);
771
            }else{
772
                monitor.done();
773
                result.setAbort();
774
                break;
775
            }
776
        }
777
        if (!monitor.isCanceled()){
778
            monitor.subTask("saving and reindex");
779
            dao.saveOrUpdateAll(nodes);
780
        }else{
781
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
782
        }
783

    
784
        monitor.done();
785
        return result;
786
    }
787

    
788
    @Override
789
    public Pager<TaxonNodeAgentRelation> pageTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,
790
            UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
791

    
792

    
793
        List<TaxonNodeAgentRelation> records = null;
794

    
795
        long count = dao.countTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid);
796
        if(PagerUtils.hasResultsInRange(count, pageIndex, pageSize)) {
797
            records = dao.listTaxonNodeAgentRelations(taxonUuid, classificationUuid,
798
                    agentUuid, rankUuid, relTypeUuid, PagerUtils.startFor(pageSize, pageIndex), PagerUtils.limitFor(pageSize), propertyPaths);
799
        }
800

    
801
        Pager<TaxonNodeAgentRelation> pager = new DefaultPagerImpl<>(pageIndex, count, pageSize, records);
802
        return pager;
803
    }
804

    
805
    @Override
806
    @Transactional
807
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, Taxon newTaxon, Reference ref, String microref){
808
        UpdateResult result = new UpdateResult();
809
        if (newTaxon.getName().getId() != 0){
810
            TaxonName name = nameService.load(newTaxon.getName().getUuid());
811
            newTaxon.setName(name);
812
        }else{
813
            for (HybridRelationship rel : newTaxon.getName().getHybridChildRelations()){
814
                if (!rel.getHybridName().isPersited()) {
815
                    nameService.save(rel.getHybridName());
816
                }
817
                if (!rel.getParentName().isPersited()) {
818
                    nameService.save(rel.getParentName());
819
                }
820
            }
821
        }
822
        UUID taxonUUID = taxonService.saveOrUpdate(newTaxon);
823
        newTaxon = (Taxon) taxonService.load(taxonUUID);
824

    
825
        TaxonNode parent = dao.load(parentNodeUuid);
826
        TaxonNode child = null;
827
        try{
828
            child = parent.addChildTaxon(newTaxon,ref, microref);
829
        }catch(Exception e){
830
            result.addException(e);
831
            result.setError();
832
            return result;
833
        }
834
        child = dao.save(child);
835

    
836
        result.addUpdatedObject(parent);
837
        if (child != null){
838
            result.setCdmEntity(child);
839
        }
840
        return result;
841

    
842
    }
843

    
844

    
845
    @Override
846
    @Transactional
847
    public UpdateResult saveNewTaxonNode(TaxonNode newTaxonNode){
848
        UpdateResult result = new UpdateResult();
849
        UUID parentUuid = newTaxonNode.getParent().getUuid();
850
        Taxon taxon = null;
851

    
852
        if (newTaxonNode.getTaxon().getId() != 0){
853
            taxon = (Taxon)taxonService.load(newTaxonNode.getTaxon().getUuid());
854
            //newTaxonNode.setTaxon(taxon);
855
        }else if (newTaxonNode.getTaxon().getName().getId() != 0){
856
            TaxonName name = nameService.load(newTaxonNode.getTaxon().getName().getUuid());
857
            taxon = newTaxonNode.getTaxon();
858
            taxon.setName(name);
859
        }else{
860
            for (HybridRelationship rel : newTaxonNode.getTaxon().getName().getHybridChildRelations()){
861
                if (!rel.getHybridName().isPersited()) {
862
                    nameService.save(rel.getHybridName());
863
                }
864
                if (!rel.getParentName().isPersited()) {
865
                    nameService.save(rel.getParentName());
866
                }
867
            }
868
        }
869
        if (taxon == null){
870
            taxon = newTaxonNode.getTaxon();
871
        }
872
        taxon.removeTaxonNode(newTaxonNode);
873
        if (taxon.getId() == 0){
874
            UUID taxonUUID = taxonService.saveOrUpdate(taxon);
875
            taxon = (Taxon) taxonService.load(taxonUUID);
876

    
877
        }
878

    
879

    
880
        TaxonNode parent = dao.load(parentUuid);
881
        TaxonNode child = null;
882
        try{
883
            child = parent.addChildTaxon(taxon, newTaxonNode.getReference(), newTaxonNode.getMicroReference());
884

    
885
        }catch(Exception e){
886
            result.addException(e);
887
            result.setError();
888
            return result;
889
        }
890

    
891
        child.setUnplaced(newTaxonNode.isUnplaced());
892
        child.setExcluded(newTaxonNode.isExcluded());
893
        for (TaxonNodeAgentRelation agentRel :newTaxonNode.getAgentRelations()){
894
            child.addAgentRelation(agentRel.getType(), agentRel.getAgent());
895
        }
896
        for (Entry<Language, LanguageString> entry: newTaxonNode.getExcludedNote().entrySet()){
897
            child.putExcludedNote(entry.getKey(), entry.getValue().getText());
898
        }
899

    
900
        newTaxonNode = null;
901
        dao.saveOrUpdate(child);
902

    
903
        result.addUpdatedObject(child.getParent());
904
        if (child != null){
905
            result.setCdmEntity(child);
906
        }
907
        return result;
908

    
909

    
910
    }
911

    
912

    
913

    
914
    @Override
915
    @Transactional
916
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, UUID taxonUuid, Reference ref, String microref){
917
        UpdateResult result = new UpdateResult();
918
        TaxonNode parent = dao.load(parentNodeUuid);
919
        Taxon taxon = (Taxon) taxonService.load(taxonUuid);
920
        TaxonNode child = null;
921
        try{
922
            child = parent.addChildTaxon(taxon, parent.getReference(), parent.getMicroReference());
923
        }catch(Exception e){
924
            result.addException(e);
925
            result.setError();
926
            return result;
927
        }
928
//        child = dao.save(child);
929

    
930
//        dao.saveOrUpdate(child);
931
        result.addUpdatedObject(parent);
932
        if (child != null){
933
            result.setCdmEntity(child);
934
        }
935
        return result;
936

    
937
    }
938

    
939
    @Override
940
    @Transactional
941
    public UpdateResult addTaxonNodeAgentRelation(UUID taxonNodeUUID, UUID agentUUID, DefinedTerm relationshipType){
942
        UpdateResult result = new UpdateResult();
943
        TaxonNode node = dao.load(taxonNodeUUID);
944
        TeamOrPersonBase<?> agent = (TeamOrPersonBase<?>) agentService.load(agentUUID);
945
        node.addAgentRelation(relationshipType, agent);
946
        try{
947
            dao.merge(node, true);
948
        }catch (Exception e){
949
            result.setError();
950
            result.addException(e);
951
        }
952
        result.setCdmEntity(node);
953
        return result;
954
    }
955

    
956
    @Override
957
    @Transactional(readOnly=false)
958
    public UpdateResult setSecundumForSubtree(SecundumForSubtreeConfigurator config) {
959
        UpdateResult result = new UpdateResult();
960
        IProgressMonitor monitor = config.getMonitor();
961

    
962
        if (monitor == null){
963
            monitor = DefaultProgressMonitor.NewInstance();
964
        }
965
        TaxonNode subTree = load(config.getSubtreeUuid());
966
        TreeIndex subTreeIndex = null;
967
        Reference newSec = null;
968
        if (config.getNewSecundum() != null){
969
            newSec = refService.load(config.getNewSecundum().getUuid());
970
        }
971

    
972
        if (config.getSubtreeUuid() == null){
973
            result.setError();
974
            result.addException(new NullPointerException("No subtree given"));
975
            monitor.done();
976
            return result;
977
        }
978

    
979
        if (subTree == null){
980
            result.setError();
981
            result.addException(new NullPointerException("Subtree does not exist"));
982
            monitor.done();
983
            return result;
984
        }else{
985
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
986
            int count = config.isIncludeAcceptedTaxa() ? dao.countSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail()):0;
987
            count += config.isIncludeSynonyms() ? dao.countSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail()) :0;
988
            monitor.beginTask("Update Secundum Reference", count);
989
        }
990

    
991
        //Reference ref = config.getNewSecundum();
992
        if (config.isIncludeAcceptedTaxa()){
993
            monitor.subTask("Update Accepted Taxa");
994

    
995
            Set<TaxonBase> updatedTaxa = dao.setSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail(), monitor);
996
            result.addUpdatedObjects(updatedTaxa);
997
        }
998
        if (config.isIncludeSynonyms()){
999
           monitor.subTask("Update Synonyms");
1000
           Set<TaxonBase> updatedSynonyms = dao.setSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail(), monitor);
1001
           result.addUpdatedObjects(updatedSynonyms);
1002
        }
1003

    
1004
        monitor.done();
1005
        return result;
1006
    }
1007

    
1008

    
1009
    /**
1010
     * {@inheritDoc}
1011
     */
1012
    @Override
1013
    @Transactional(readOnly=false)
1014
    public UpdateResult setPublishForSubtree(UUID subtreeUuid, boolean publish, boolean includeAcceptedTaxa,
1015
            boolean includeSynonyms, boolean includeSharedTaxa, IProgressMonitor monitor) {
1016
        UpdateResult result = new UpdateResult();
1017
        if (monitor == null){
1018
            monitor = DefaultProgressMonitor.NewInstance();
1019
        }
1020
        TreeIndex subTreeIndex = null;
1021

    
1022
        if (subtreeUuid == null){
1023
            result.setError();
1024
            result.addException(new NullPointerException("No subtree given"));
1025
            monitor.done();
1026
            return result;
1027
        }
1028
        TaxonNode subTree = find(subtreeUuid);
1029
        if (subTree == null){
1030
            result.setError();
1031
            result.addException(new NullPointerException("Subtree does not exist"));
1032
            monitor.done();
1033
            return result;
1034
        }else{
1035
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
1036
            int count = includeAcceptedTaxa ? dao.countPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa):0;
1037
            count += includeSynonyms ? dao.countPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa):0;
1038
            monitor.beginTask("Update publish flag", count);
1039
        }
1040

    
1041

    
1042
        if (includeAcceptedTaxa){
1043
            monitor.subTask("Update Accepted Taxa");
1044
            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa, monitor);
1045
            result.addUpdatedObjects(updatedTaxa);
1046
        }
1047
        if (includeSynonyms){
1048
            monitor.subTask("Update Synonyms");
1049
            Set<TaxonBase> updatedSynonyms = dao.setPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa, monitor);
1050
            result.addUpdatedObjects(updatedSynonyms);
1051
        }
1052

    
1053
        monitor.done();
1054
        return result;
1055
    }
1056

    
1057

    
1058
    @Override
1059
    public long count(TaxonNodeFilter filter){
1060
        return nodeFilterDao.count(filter);
1061
    }
1062

    
1063
    @Override
1064
    public List<UUID> uuidList(TaxonNodeFilter filter){
1065
        return nodeFilterDao.listUuids(filter);
1066
    }
1067

    
1068
    @Override
1069
    public List<Integer> idList(TaxonNodeFilter filter){
1070
        return nodeFilterDao.idList(filter);
1071
    }
1072

    
1073
    @Override
1074
    public TaxonNodeDto findCommonParentDto(Collection<TaxonNodeDto> nodes) {
1075
        TaxonNodeDto commonParent = null;
1076
        List<String> treePath = null;
1077
        for (TaxonNodeDto nodeDto : nodes) {
1078
            String nodeTreeIndex = nodeDto.getTreeIndex();
1079
            nodeTreeIndex = nodeTreeIndex.replaceFirst("#", "");
1080
            String[] split = nodeTreeIndex.split("#");
1081
            if(treePath == null){
1082
                treePath = Arrays.asList(split);
1083
            }
1084
            else{
1085
                List<String> match = new ArrayList<>();
1086
                for(int i=0;i<treePath.size();i++){
1087
                    if(i>=split.length){
1088
                        //current tree index is shorter so break
1089
                        break;
1090
                    }
1091
                    else if(split[i].equals(treePath.get(i))){
1092
                        //match found
1093
                        match.add(treePath.get(i));
1094
                    }
1095
                    else{
1096
                        //first mismatch found
1097
                        break;
1098
                    }
1099
                }
1100
                treePath = match;
1101
                if(treePath.isEmpty()){
1102
                    //no common parent found for at least two nodes
1103
                    //-> they belong to a different classification
1104
                    break;
1105
                }
1106
            }
1107
        }
1108
        if(treePath!=null && !treePath.isEmpty()) {
1109
            //get last index
1110
            int nodeId = Integer.parseInt(treePath.get(treePath.size()-1));
1111
            TaxonNode taxonNode = dao.load(nodeId, null);
1112
            commonParent = new TaxonNodeDto(taxonNode);
1113
        }
1114
        return commonParent;
1115
    }
1116

    
1117
    @Override
1118
    public List<TaxonDistributionDTO> getTaxonDistributionDTOForSubtree(UUID parentNodeUuid, List<String> propertyPaths){
1119
        List<TaxonNode> nodes = listChildrenOf(load(parentNodeUuid), null, null,
1120
               true, true, propertyPaths);
1121
        List<TaxonDistributionDTO> result = new ArrayList<>();
1122
        for(TaxonNode node:nodes){
1123
            if (node.getTaxon() != null){
1124
                try{
1125
                    TaxonDistributionDTO dto = new TaxonDistributionDTO(node.getTaxon());
1126
                    result.add(dto);
1127
                }catch(Exception e){
1128
                    System.err.println(node.getTaxon().getTitleCache());
1129
                }
1130

    
1131
            }
1132

    
1133
        }
1134

    
1135
        return result;
1136
    }
1137

    
1138

    
1139

    
1140
}
(96-96/103)