Project

General

Profile

Download (49.3 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;
21
import java.util.Map.Entry;
22
import java.util.Set;
23
import java.util.UUID;
24

    
25
import org.apache.log4j.Logger;
26
import org.springframework.beans.factory.annotation.Autowired;
27
import org.springframework.security.core.Authentication;
28
import org.springframework.stereotype.Service;
29
import org.springframework.transaction.annotation.Transactional;
30
import org.springframework.transaction.interceptor.TransactionAspectSupport;
31

    
32
import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
33
import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;
34
import eu.etaxonomy.cdm.api.service.config.PublishForSubtreeConfigurator;
35
import eu.etaxonomy.cdm.api.service.config.SecundumForSubtreeConfigurator;
36
import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
37
import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator;
38
import eu.etaxonomy.cdm.api.service.dto.CdmEntityIdentifier;
39
import eu.etaxonomy.cdm.api.service.dto.CreateTaxonDTO;
40
import eu.etaxonomy.cdm.api.service.dto.TaxonDistributionDTO;
41
import eu.etaxonomy.cdm.api.service.pager.Pager;
42
import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
43
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
44
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
45
import eu.etaxonomy.cdm.common.monitor.DefaultProgressMonitor;
46
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
47
import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
48
import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
49
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
50
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
51
import eu.etaxonomy.cdm.model.common.CdmBase;
52
import eu.etaxonomy.cdm.model.common.Language;
53
import eu.etaxonomy.cdm.model.common.LanguageString;
54
import eu.etaxonomy.cdm.model.common.TreeIndex;
55
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
56
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
57
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
58
import eu.etaxonomy.cdm.model.description.TaxonDescription;
59
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
60
import eu.etaxonomy.cdm.model.name.HybridRelationship;
61
import eu.etaxonomy.cdm.model.name.Rank;
62
import eu.etaxonomy.cdm.model.name.TaxonName;
63
import eu.etaxonomy.cdm.model.permission.Operation;
64
import eu.etaxonomy.cdm.model.reference.Reference;
65
import eu.etaxonomy.cdm.model.taxon.Classification;
66
import eu.etaxonomy.cdm.model.taxon.HomotypicGroupTaxonComparator;
67
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
68
import eu.etaxonomy.cdm.model.taxon.Synonym;
69
import eu.etaxonomy.cdm.model.taxon.SynonymType;
70
import eu.etaxonomy.cdm.model.taxon.Taxon;
71
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
72
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
73
import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
74
import eu.etaxonomy.cdm.model.taxon.TaxonNodeStatus;
75
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
76
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
77
import eu.etaxonomy.cdm.model.term.DefinedTerm;
78
import eu.etaxonomy.cdm.persistence.dao.common.Restriction;
79
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
80
import eu.etaxonomy.cdm.persistence.dao.reference.IOriginalSourceDao;
81
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
82
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeFilterDao;
83
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
84
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
85
import eu.etaxonomy.cdm.persistence.permission.ICdmPermissionEvaluator;
86
import eu.etaxonomy.cdm.persistence.query.OrderHint;
87

    
88
/**
89
 * @author n.hoffmann
90
 * @since Apr 9, 2010
91
 */
92
@Service
93
@Transactional(readOnly = true)
94
public class TaxonNodeServiceImpl
95
           extends AnnotatableServiceBase<TaxonNode, ITaxonNodeDao>
96
           implements ITaxonNodeService{
97
    private static final Logger logger = Logger.getLogger(TaxonNodeServiceImpl.class);
98

    
99
    @Autowired
100
    private IBeanInitializer defaultBeanInitializer;
101

    
102
    @Autowired
103
    private ITaxonService taxonService;
104

    
105
    @Autowired
106
    private IReferenceService referenceService;
107

    
108
    @Autowired
109
    private IDescriptiveDataSetService dataSetService;
110

    
111
    @Autowired
112
    private IAgentService agentService;
113

    
114
    @Autowired
115
    private INameService nameService;
116

    
117
    @Autowired
118
    private IOriginalSourceDao sourceDao;
119

    
120

    
121
    @Autowired
122
    private ITaxonNodeFilterDao nodeFilterDao;
123

    
124
    @Autowired
125
    IProgressMonitorService progressMonitorService;
126

    
127
    @Autowired
128
    private ICdmPermissionEvaluator permissionEvaluator;
129

    
130
    @Override
131
    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
132
            List<String> propertyPaths, boolean recursive,  boolean includeUnpublished,
133
            TaxonNodeSortMode sortMode) {
134

    
135
        getSession().refresh(taxonNode);
136
        List<TaxonNode> childNodes;
137
        if (recursive == true){
138
        	childNodes  = dao.listChildrenOf(taxonNode, null, null, recursive, includeUnpublished, null);
139
        }else if (includeUnpublished){
140
            childNodes = new ArrayList<>(taxonNode.getChildNodes());
141
        }else{
142
            childNodes = new ArrayList<>();
143
            for (TaxonNode node:taxonNode.getChildNodes()){
144
                if (node.getTaxon().isPublish()){
145
                    childNodes.add(node);
146
                }
147
            }
148
        }
149

    
150
        HHH_9751_Util.removeAllNull(childNodes);
151

    
152
        if (sortMode != null){
153
            Comparator<TaxonNode> comparator = sortMode.newComparator();
154
        	Collections.sort(childNodes, comparator);
155
        }
156
        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
157
        return childNodes;
158
    }
159

    
160
    @Override
161
    public List<TaxonNode> listChildrenOf(TaxonNode node, Integer pageSize, Integer pageIndex,
162
            boolean recursive, boolean includeUnpublished, List<String> propertyPaths){
163
        return dao.listChildrenOf(node, pageSize, pageIndex, recursive, includeUnpublished, propertyPaths);
164
    }
165

    
166
    @Override
167
    public TaxonNodeDto getParentUuidAndTitleCache(ITaxonTreeNode child) {
168
        UUID uuid = child.getUuid();
169
        int id = child.getId();
170
        TaxonNodeDto uuidAndTitleCache = new TaxonNodeDto(uuid, id, null);
171
        return getParentUuidAndTitleCache(uuidAndTitleCache);
172
    }
173

    
174
    @Override
175
    public TaxonNodeDto getParentUuidAndTitleCache(TaxonNodeDto child) {
176
        return dao.getParentUuidAndTitleCache(child);
177
    }
178

    
179
    @Override
180
    public List<TaxonNodeDto> listChildNodesAsTaxonNodeDto(TaxonNodeDto parent) {
181
        return dao.listChildNodesAsTaxonNodeDto(parent);
182
    }
183

    
184
    @Override
185
    public List<TaxonNodeDto> getUuidAndTitleCache(Integer limit, String pattern, UUID classificationUuid) {
186
        return dao.getUuidAndTitleCache(limit, pattern, classificationUuid, true);
187
    }
188

    
189
    @Override
190
    public List<TaxonNodeDto> listChildNodesAsTaxonNodeDto(ITaxonTreeNode parent) {
191
        List<String> propertyPaths = new ArrayList<>();
192
        propertyPaths.add("parent");
193
        parent = dao.load(parent.getId(), propertyPaths);
194
        TaxonNodeDto uuidAndTitleCache = new TaxonNodeDto(parent);
195
        return listChildNodesAsTaxonNodeDto(uuidAndTitleCache);
196
    }
197

    
198
    @Override
199
    public List<TaxonNodeDto> taxonNodeDtoParentRank(Classification classification, Rank rank, TaxonName name) {
200
    	return dao.getParentTaxonNodeDtoForRank(classification, rank, name);
201
    }
202

    
203
    @Override
204
    public List<TaxonNodeDto> taxonNodeDtoParentRank(Classification classification, Rank rank, TaxonBase<?> taxonBase) {
205
        return dao.getParentTaxonNodeDtoForRank(classification, rank, taxonBase);
206
    }
207

    
208
    @Override
209
    public Pager<TaxonNodeDto> pageChildNodesDTOs(UUID taxonNodeUuid, boolean recursive,  boolean includeUnpublished,
210
            boolean doSynonyms, TaxonNodeSortMode sortMode,
211
            Integer pageSize, Integer pageIndex) {
212

    
213
        TaxonNode parentNode = dao.load(taxonNodeUuid);
214

    
215
        List<CdmBase> allRecords = new ArrayList<>();
216

    
217
        //acceptedTaxa
218
        List<TaxonNode> childNodes = loadChildNodesOfTaxonNode(parentNode, null, recursive, includeUnpublished, sortMode);
219
        allRecords.addAll(childNodes);
220

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

    
227
            allRecords.addAll(synList);
228
        }
229

    
230
        List<TaxonNodeDto> dtos = new ArrayList<>(pageSize==null?25:pageSize);
231
        long totalCount = Long.valueOf(allRecords.size());
232

    
233
        TaxonName parentName = null;
234

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

    
248
    @Override
249
    public TaxonNodeDto parentDto(UUID taxonNodeUuid) {
250
        if (taxonNodeUuid == null){
251
            return null;
252
        }
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
        if (taxonNodeUuid == null){
263
            return null;
264
        }
265
        TaxonNode taxonNode = dao.load(taxonNodeUuid);
266
        if (taxonNode != null){
267
            return new TaxonNodeDto(taxonNode);
268
        }
269
        return null;
270
    }
271

    
272
    @Override
273
    @Autowired
274
    protected void setDao(ITaxonNodeDao dao) {
275
        this.dao = dao;
276
    }
277

    
278
    @Override
279
    @Transactional(readOnly = false)
280
    public DeleteResult makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode,
281
            SynonymType synonymType, Reference citation, String citationMicroReference, boolean setNameInSource)  {
282

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

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

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

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

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

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

    
342
            }
343

    
344
            newAcceptedTaxon.addSynonym(synonym, srt);
345

    
346

    
347
            /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymType.HETEROTYPIC_SYNONYM_OF())){
348
            	homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
349
            }*/
350

    
351
        }
352

    
353

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

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

    
373
            }else if(toTaxon == oldTaxon){
374
               fromTaxon.addTaxonRelation(newAcceptedTaxon, taxonRelationship.getType(),
375
                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
376
               taxonService.saveOrUpdate(fromTaxon);
377

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

    
383
            fromTaxon.removeTaxonRelation(taxonRelationship);
384
            toTaxon.removeTaxonRelation(taxonRelationship);
385
            taxonRelationship.setToTaxon(null);
386
            taxonRelationship.setFromTaxon(null);
387
        }
388

    
389
        //Move descriptions to new taxon
390
        List<TaxonDescription> descriptions = new ArrayList<TaxonDescription>( oldTaxon.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())
391
        for(TaxonDescription description : descriptions){
392
            String message = "Description copied from former accepted taxon: %s (Old title: %s)";
393
            message = String.format(message, oldTaxon.getTitleCache(), description.getTitleCache());
394
            description.setTitleCache(message, true);
395
            if (setNameInSource) {
396
                for (DescriptionElementBase element: description.getElements()){
397
                    for (DescriptionElementSource source: element.getSources()){
398
                        if (source.getNameUsedInSource() == null){
399
                            source.setNameUsedInSource(newSynonymName);
400
                        }
401
                    }
402
                }
403
            }
404
            //oldTaxon.removeDescription(description, false);
405
            newAcceptedTaxon.addDescription(description);
406
        }
407
        oldTaxon.clearDescriptions();
408

    
409
        taxonService.saveOrUpdate(newAcceptedTaxon);
410

    
411
        taxonService.saveOrUpdate(oldTaxon);
412
        taxonService.getSession().flush();
413

    
414
        TaxonDeletionConfigurator conf = new TaxonDeletionConfigurator();
415
        conf.setDeleteSynonymsIfPossible(false);
416
        conf.setDeleteNameIfPossible(false);
417
        DeleteResult result = taxonService.isDeletable(oldTaxon.getUuid(), conf);
418

    
419

    
420
        if (result.isOk()){
421
        	 result = taxonService.deleteTaxon(oldTaxon.getUuid(), conf, classification.getUuid());
422

    
423
        }else{
424
        	result.setStatus(Status.OK);
425
        	TaxonNodeDeletionConfigurator config = new TaxonNodeDeletionConfigurator();
426
        	config.setDeleteElement(false);
427
        	conf.setTaxonNodeConfig(config);
428
        	result.includeResult(deleteTaxonNode(oldTaxonNode, conf));
429
        }
430

    
431
        result.addUpdatedObject(newAcceptedTaxon);
432

    
433

    
434
        //oldTaxonNode.delete();
435
        return result;
436
    }
437
    @Override
438
    @Transactional(readOnly = false)
439
    public UpdateResult makeTaxonNodeSynonymsOfAnotherTaxonNode( Set<UUID> oldTaxonNodeUuids,
440
            UUID newAcceptedTaxonNodeUUIDs,
441
            SynonymType synonymType,
442
            Reference citation,
443
            String citationMicroReference,
444
            boolean setNameInSource) {
445
    	UpdateResult result = new UpdateResult();
446
    	for (UUID nodeUuid: oldTaxonNodeUuids) {
447
    		result.includeResult(makeTaxonNodeASynonymOfAnotherTaxonNode(nodeUuid, newAcceptedTaxonNodeUUIDs, synonymType, citation, citationMicroReference, setNameInSource));
448
    	}
449
    	return result;
450
    }
451

    
452
    @Override
453
    @Transactional(readOnly = false)
454
    public UpdateResult makeTaxonNodeASynonymOfAnotherTaxonNode(UUID oldTaxonNodeUuid,
455
            UUID newAcceptedTaxonNodeUUID,
456
            SynonymType synonymType,
457
            Reference citation,
458
            String citationMicroReference,
459
            boolean setNameInSource) {
460

    
461
        TaxonNode oldTaxonNode = dao.load(oldTaxonNodeUuid);
462
        TaxonNode oldTaxonParentNode = oldTaxonNode.getParent();
463
        TaxonNode newTaxonNode = dao.load(newAcceptedTaxonNodeUUID);
464

    
465
        UpdateResult result = makeTaxonNodeASynonymOfAnotherTaxonNode(oldTaxonNode,
466
                newTaxonNode,
467
                synonymType,
468
                citation,
469
                citationMicroReference, setNameInSource);
470
        result.addUpdatedCdmId(new CdmEntityIdentifier(oldTaxonParentNode.getId(), TaxonNode.class));
471
        result.addUpdatedCdmId(new CdmEntityIdentifier(newTaxonNode.getId(), TaxonNode.class));
472
        result.setCdmEntity(oldTaxonParentNode);
473
        return result;
474
    }
475

    
476
    @Override
477
    @Transactional(readOnly = false)
478
    public DeleteResult deleteTaxonNodes(List<TaxonNode> list, TaxonDeletionConfigurator config) {
479

    
480
        if (config == null){
481
        	config = new TaxonDeletionConfigurator();
482
        }
483
        DeleteResult result = new DeleteResult();
484
        Classification classification = null;
485
        List<TaxonNode> taxonNodes = new ArrayList<>(list);
486

    
487
        for (TaxonNode treeNode:taxonNodes){
488
        	if (treeNode != null){
489

    
490
        		TaxonNode taxonNode;
491
	            taxonNode = CdmBase.deproxy(treeNode);
492
	            TaxonNode parent = taxonNode.getParent();
493
	            	//check whether the node has children or the children are already deleted
494
	            if(taxonNode.hasChildNodes()) {
495
            		List<TaxonNode> children = new ArrayList<> ();
496
            		List<TaxonNode> childNodesList = taxonNode.getChildNodes();
497
        			children.addAll(childNodesList);
498
        			//To avoid NPE when child is also in list of taxonNodes, remove it from the list
499
        			Iterator<TaxonNode> it = taxonNodes.iterator();
500
        			for (TaxonNode child: children) {
501
        				while (it.hasNext()) {
502
        					if (it.next().equals(child)) {
503
        						it.remove();
504
        					}
505
        				}
506
        			}
507
        			int compare = config.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling.DELETE);
508
        			boolean childHandling = (compare == 0)? true: false;
509
            		if (childHandling){
510
            			boolean changeDeleteTaxon = false;
511
            			if (!config.getTaxonNodeConfig().isDeleteTaxon()){
512
            				config.getTaxonNodeConfig().setDeleteTaxon(true);
513
            				changeDeleteTaxon = true;
514
            			}
515
            			DeleteResult resultNodes = deleteTaxonNodes(children, config);
516
            			if (!resultNodes.isOk()){
517
                            result.addExceptions(resultNodes.getExceptions());
518
                            result.setStatus(resultNodes.getStatus());
519
                        }
520
            			if (changeDeleteTaxon){
521
            				config.getTaxonNodeConfig().setDeleteTaxon(false);
522
            			}
523

    
524
            		} else {
525
            			//move the children to the parent
526

    
527
            			for (TaxonNode child: childNodesList){
528
            				parent.addChildNode(child, child.getReference(), child.getMicroReference());
529
            			}
530

    
531
            		}
532
            	}
533

    
534
	            classification = taxonNode.getClassification();
535

    
536
	            if (classification.getRootNode().equals(taxonNode)){
537
	            	classification.removeRootNode();
538
	            	classification = null;
539
	            }else if (classification.getChildNodes().contains(taxonNode)){
540
            		Taxon taxon = taxonNode.getTaxon();
541
            		classification.deleteChildNode(taxonNode);
542

    
543
	            	//node is rootNode
544
	            	if (taxon != null){
545

    
546
	            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
547
	            		    taxonService.saveOrUpdate(taxon);
548
	            		    saveOrUpdate(taxonNode);
549

    
550
			            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
551
			            	configNew.setClassificationUuid(classification.getUuid());
552
			            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, classification.getUuid());
553
			            	if (!resultTaxon.isOk()){
554
                                result.addExceptions(resultTaxon.getExceptions());
555
                                result.setStatus(resultTaxon.getStatus());
556
                            }
557

    
558
		            	}
559
	            	}
560
            		classification = null;
561

    
562
	            } else {
563
	            	//classification = null;
564
	            	Taxon taxon = taxonNode.getTaxon();
565
	            	taxon = CdmBase.deproxy(taxon);
566
	            	if (taxon != null){
567
	            		taxon.removeTaxonNode(taxonNode);
568
	            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
569
			            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
570
			            	saveOrUpdate(taxonNode);
571
			            	taxonService.saveOrUpdate(taxon);
572
			            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, classification.getUuid());
573

    
574
                            if (!resultTaxon.isOk()){
575
                                result.addExceptions(resultTaxon.getExceptions());
576
                                result.setStatus(resultTaxon.getStatus());
577
                            }
578
		            	}
579
	            	}
580

    
581
	            }
582

    
583
	            result.addUpdatedObject(parent);
584
	            if(result.getCdmEntity() == null){
585
	                result.setCdmEntity(taxonNode);
586
                }
587
	            UUID uuid = dao.delete(taxonNode);
588
	            logger.debug("Deleted node " +uuid.toString());
589

    
590
	        }
591
        }
592
        /*if (classification != null){
593
            result.addUpdatedObject(classification);
594
        	DeleteResult resultClassification = classService.delete(classification);
595
        	 if (!resultClassification.isOk()){
596
                 result.addExceptions(resultClassification.getExceptions());
597
                 result.setStatus(resultClassification.getStatus());
598
             }
599
        }*/
600
        return result;
601
    }
602

    
603

    
604
    @Override
605
    @Transactional(readOnly = false)
606
    public DeleteResult deleteTaxonNodes(Collection<UUID> nodeUuids, TaxonDeletionConfigurator config) {
607
        List<TaxonNode> nodes = new ArrayList<>();
608
        for(UUID nodeUuid : nodeUuids) {
609
            nodes.add(dao.load(nodeUuid));
610
        }
611
        return deleteTaxonNodes(nodes, config);
612
    }
613

    
614

    
615
    @Override
616
    @Transactional(readOnly = false)
617
    public DeleteResult deleteTaxonNode(UUID nodeUUID, TaxonDeletionConfigurator config) {
618

    
619
    	TaxonNode node = CdmBase.deproxy(dao.load(nodeUUID));
620
    	return deleteTaxonNode(node, config);
621
    }
622

    
623
    @Override
624
    @Transactional(readOnly = false)
625
    public DeleteResult deleteTaxonNode(TaxonNode node, TaxonDeletionConfigurator config) {
626
        DeleteResult result = new DeleteResult();
627
        if (node == null){
628
            result.setAbort();
629
            result.addException(new Exception("The TaxonNode was already deleted."));
630
            return result;
631
        }
632
        Taxon taxon = null;
633
        try{
634
            taxon = HibernateProxyHelper.deproxy(node.getTaxon());
635
        }catch(NullPointerException e){
636
            result.setAbort();
637
            result.addException(new Exception("The Taxon was already deleted."));
638

    
639
        }
640

    
641

    
642
    	TaxonNode parent = HibernateProxyHelper.deproxy(node.getParent(), TaxonNode.class);
643
    	if (config == null){
644
    		config = new TaxonDeletionConfigurator();
645
    	}
646

    
647

    
648
    	if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.MOVE_TO_PARENT)){
649
    	   Object[] children = node.getChildNodes().toArray();
650
    	   TaxonNode childNode;
651
    	   for (Object child: children){
652
    	       childNode = (TaxonNode) child;
653
    	       parent.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference());
654

    
655
    	   }
656
    	}else{
657
    	    result.includeResult(deleteTaxonNodes(node.getChildNodes(), config));
658
    	}
659

    
660
    	//remove node from DescriptiveDataSet
661
        commonService.getReferencingObjects(node).stream()
662
        .filter(obj->obj instanceof DescriptiveDataSet)
663
        .forEach(dataSet->{
664
            ((DescriptiveDataSet)dataSet).removeTaxonSubtree(node);
665
            dataSetService.saveOrUpdate((DescriptiveDataSet) dataSet);
666
        });
667

    
668
    	if (taxon != null){
669
        	if (config.getTaxonNodeConfig().isDeleteTaxon() && (config.isDeleteInAllClassifications() || taxon.getTaxonNodes().size() == 1)){
670
        		result = taxonService.deleteTaxon(taxon.getUuid(), config, node.getClassification().getUuid());
671
        		result.addUpdatedObject(parent);
672
        		if (result.isOk()){
673
        			return result;
674
        		}
675
        	} else {
676
        	    result.addUpdatedObject(taxon);
677
        	}
678
    	}
679
    	result.setCdmEntity(node);
680
    	boolean success = true;
681
    	if (taxon != null){
682
    	    success = taxon.removeTaxonNode(node);
683
    	    taxonService.saveOrUpdate(taxon);
684
    	}
685
    	dao.saveOrUpdate(parent);
686

    
687
    	result.addUpdatedObject(parent);
688

    
689
    	if (success){
690
			result.setStatus(Status.OK);
691
			if (parent != null){
692
    			parent = HibernateProxyHelper.deproxy(parent, TaxonNode.class);
693
    			int index = parent.getChildNodes().indexOf(node);
694
    			if (index > -1){
695
    			    parent.removeChild(index);
696
    			}
697
			}
698
    		if (!dao.delete(node, config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)).equals(null)){
699
    		    result.getUpdatedObjects().remove(node);
700
    			result.addDeletedObject(node);
701
    			return result;
702
    		} else {
703
    			result.setError();
704
    			return result;
705
    		}
706
    	}else{
707
    	    if (dao.findByUuid(node.getUuid()) != null){
708
        		result.setError();
709
        		result.addException(new Exception("The node can not be removed from the taxon."));
710
    		}
711
    		return result;
712
    	}
713
    }
714

    
715

    
716
    @Override
717
    public List<TaxonNode> listAllNodesForClassification(Classification classification, Integer start, Integer end) {
718
        return dao.getTaxonOfAcceptedTaxaByClassification(classification, start, end);
719
    }
720

    
721
    @Override
722
    public int countAllNodesForClassification(Classification classification) {
723
        return dao.countTaxonOfAcceptedTaxaByClassification(classification);
724
    }
725

    
726
    @Override
727
    @Transactional
728
    public UpdateResult moveTaxonNode(UUID taxonNodeUuid, UUID targetNodeUuid, int movingType){
729
        TaxonNode taxonNode = HibernateProxyHelper.deproxy(dao.load(taxonNodeUuid));
730
    	TaxonNode targetNode = HibernateProxyHelper.deproxy(dao.load(targetNodeUuid));
731
    	UpdateResult result = moveTaxonNode(taxonNode, targetNode, movingType);
732
    	return result;
733
    }
734

    
735
    @Override
736
    @Transactional
737
    public UpdateResult moveTaxonNode(TaxonNode taxonNode, TaxonNode newParent, int movingType){
738
        UpdateResult result = new UpdateResult();
739

    
740
        TaxonNode parentParent = HibernateProxyHelper.deproxy(newParent.getParent());
741
        Integer sortIndex = -1;
742
        if (movingType == 0){
743
            sortIndex = 0;
744
        }else if (movingType == 1){
745
            sortIndex = newParent.getSortIndex();
746
            newParent = parentParent;
747
        } else if (movingType == 2){
748
            sortIndex = newParent.getSortIndex() +1;
749
            newParent = parentParent;
750
        } else{
751
            result.setAbort();
752
            result.addException(new Exception("The moving type "+ movingType +" is not supported."));
753
        }
754

    
755
        taxonNode = newParent.addChildNode(taxonNode, sortIndex, taxonNode.getReference(),  taxonNode.getMicroReference());
756
        result.addUpdatedObject(taxonNode);
757

    
758
        return result;
759
    }
760

    
761
    @Override
762
    @Transactional
763
    public UpdateResult moveTaxonNodes(Set<UUID> taxonNodeUuids, UUID newParentNodeUuid, int movingType, IProgressMonitor monitor){
764

    
765
        if (monitor == null){
766
            monitor = DefaultProgressMonitor.NewInstance();
767
        }
768
        UpdateResult result = new UpdateResult();
769

    
770
        TaxonNode targetNode = dao.load(newParentNodeUuid);
771
        List<TaxonNode> nodes = dao.list(taxonNodeUuids, null, null, null, null);
772

    
773
        monitor.beginTask("Move Taxonnodes", nodes.size()*2);
774
        monitor.subTask("move taxon nodes");
775
        for (TaxonNode node: nodes){
776
            if (!monitor.isCanceled()){
777
                if (!nodes.contains(node.getParent())){
778
                    result.includeResult(moveTaxonNode(node,targetNode, movingType));
779
                }
780
                monitor.worked(1);
781
            }else{
782
                monitor.done();
783
                result.setAbort();
784
                break;
785
            }
786
        }
787
        if (!monitor.isCanceled()){
788
            monitor.subTask("saving and reindex");
789
            dao.saveOrUpdateAll(nodes);
790
        }else{
791
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
792
        }
793

    
794
        monitor.done();
795
        return result;
796
    }
797

    
798
    @Override
799
    public Pager<TaxonNodeAgentRelation> pageTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,
800
            UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
801

    
802

    
803
        List<TaxonNodeAgentRelation> records = null;
804

    
805
        long count = dao.countTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid);
806
        if(PagerUtils.hasResultsInRange(count, pageIndex, pageSize)) {
807
            records = dao.listTaxonNodeAgentRelations(taxonUuid, classificationUuid,
808
                    agentUuid, rankUuid, relTypeUuid, PagerUtils.startFor(pageSize, pageIndex), PagerUtils.limitFor(pageSize), propertyPaths);
809
        }
810

    
811
        Pager<TaxonNodeAgentRelation> pager = new DefaultPagerImpl<>(pageIndex, count, pageSize, records);
812
        return pager;
813
    }
814

    
815
    @Override
816
    @Transactional
817
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, CreateTaxonDTO taxonDto,
818
            DescriptionElementSource source, String microref,
819
            TaxonNodeStatus status, Map<Language,LanguageString> statusNote){
820

    
821
        UpdateResult result = new UpdateResult();
822
        TaxonName name = null;
823
        if (taxonDto.getNameUuid() != null){
824
            name = nameService.load(taxonDto.getNameUuid());
825

    
826
        }else{
827
            UpdateResult tmpResult = nameService.parseName(taxonDto.getTaxonNameString(),
828
                    taxonDto.getCode(), taxonDto.getPreferredRank(),  true);
829
            result.addUpdatedObjects(tmpResult.getUpdatedObjects());
830
            name = (TaxonName)tmpResult.getCdmEntity();
831
        }
832
        Reference sec = null;
833
        if (taxonDto.getSecUuid() != null ){
834
            sec = referenceService.load(taxonDto.getSecUuid());
835
        }
836
        if (!name.isPersited()){
837
            for (HybridRelationship rel : name.getHybridChildRelations()){
838
                if (!rel.getHybridName().isPersited()) {
839
                    nameService.save(rel.getHybridName());
840
                }
841
                if (!rel.getParentName().isPersited()) {
842
                    nameService.save(rel.getParentName());
843
                }
844
            }
845
        }
846

    
847
       Taxon newTaxon = Taxon.NewInstance(name, sec);
848
       newTaxon.setPublish(taxonDto.isPublish());
849
//       UUID taxonUuid = taxonService.saveOrUpdate(newTaxon);
850
//       newTaxon = (Taxon) taxonService.load(taxonUuid);
851

    
852
       TaxonNode parent = dao.load(parentNodeUuid);
853
       TaxonNode child = null;
854
       Reference ref = null;
855
       if (source != null){
856
           if (source.isPersited()){
857
               source = (DescriptionElementSource) sourceDao.load(source.getUuid());
858
           }
859
           if (source.getCitation() != null){
860
               source.setCitation(referenceService.load(source.getCitation().getUuid()));
861
           }
862
           if (source.getNameUsedInSource() !=null){
863
               source.setNameUsedInSource(nameService.load(source.getNameUsedInSource().getUuid()));
864
           }
865
       }
866

    
867
       try{
868
           child = parent.addChildTaxon(newTaxon, source);
869
           child.setStatus(status);
870

    
871
           if (statusNote != null){
872
               child.getStatusNote().putAll(statusNote);
873
           }
874

    
875
        }catch(Exception e){
876
            result.addException(e);
877
            result.setError();
878
            return result;
879
        }
880
        child = dao.save(child);
881

    
882
        result.addUpdatedObject(parent);
883
        if (child != null){
884
            result.setCdmEntity(child);
885
        }
886
        return result;
887
    }
888

    
889
    @Override
890
    @Transactional
891
    public UpdateResult saveNewTaxonNode(TaxonNode newTaxonNode){
892
        UpdateResult result = new UpdateResult();
893
        UUID parentUuid = newTaxonNode.getParent().getUuid();
894
        Taxon taxon = null;
895

    
896
        if (newTaxonNode.getTaxon().isPersited()){
897
            taxon = (Taxon)taxonService.load(newTaxonNode.getTaxon().getUuid());
898
        }else if (newTaxonNode.getTaxon().getName().isPersited()){
899
            TaxonName name = nameService.load(newTaxonNode.getTaxon().getName().getUuid());
900
            taxon = newTaxonNode.getTaxon();
901
            taxon.setName(name);
902
        }else{
903
            //taxon and name is not persisted, persist possible related names
904
            for (HybridRelationship rel : newTaxonNode.getTaxon().getName().getHybridChildRelations()){
905
                if (!rel.getHybridName().isPersited()) {
906
                    nameService.save(rel.getHybridName());
907
                }
908
                if (!rel.getParentName().isPersited()) {
909
                    nameService.save(rel.getParentName());
910
                }
911
            }
912
        }
913
        if (taxon == null){
914
            taxon = newTaxonNode.getTaxon();
915
        }
916
        taxon.removeTaxonNode(newTaxonNode);
917

    
918
        if (taxon.getSec() != null && taxon.getSec().isPersited()){
919
            Reference sec = referenceService.load(taxon.getSec().getUuid());
920
            taxon.setSec(sec);
921
        }
922
        if (!taxon.isPersited()){
923
            MergeResult<TaxonBase> mergeResult = taxonService.merge(taxon, true);
924
            taxon = (Taxon) mergeResult.getMergedEntity();
925

    
926
        }
927

    
928
        TaxonNode parent = dao.load(parentUuid);
929
        TaxonNode child = null;
930
        try{
931
            child = parent.addChildTaxon(taxon, newTaxonNode.getReference(), newTaxonNode.getMicroReference());
932
        }catch(Exception e){
933
            result.addException(e);
934
            result.setError();
935
            return result;
936
        }
937

    
938
        //TODO can't we work with clone method here?
939
        child.setStatus(newTaxonNode.getStatus());
940
        for (TaxonNodeAgentRelation agentRel :newTaxonNode.getAgentRelations()){
941
            child.addAgentRelation(agentRel.getType(), agentRel.getAgent());
942
        }
943
        for (Entry<Language, LanguageString> entry: newTaxonNode.getStatusNote().entrySet()){
944
            child.putStatusNote(entry.getKey(), entry.getValue().getText());
945
        }
946

    
947
        newTaxonNode = null;
948
        MergeResult<TaxonNode> mergeNode = dao.merge(child,true);
949
        child = mergeNode.getMergedEntity();
950
        result.addUpdatedObject(child.getParent());
951
        result.setCdmEntity(child);
952
        return result;
953
    }
954

    
955
    @Override
956
    @Transactional
957
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, UUID taxonUuid, UUID refUuid, String microref){
958
        UpdateResult result = new UpdateResult();
959
        TaxonNode parent = dao.load(parentNodeUuid);
960
        Taxon taxon = (Taxon) taxonService.load(taxonUuid);
961
        TaxonNode child = null;
962
        try{
963
            child = parent.addChildTaxon(taxon, parent.getReference(), parent.getMicroReference());
964
        }catch(Exception e){
965
            result.addException(e);
966
            result.setError();
967
            return result;
968
        }
969

    
970
        result.addUpdatedObject(parent);
971
        if (child != null){
972
            result.setCdmEntity(child);
973
        }
974
        return result;
975
    }
976

    
977
    @Override
978
    @Transactional
979
    public UpdateResult addTaxonNodeAgentRelation(UUID taxonNodeUUID, UUID agentUUID, DefinedTerm relationshipType){
980
        UpdateResult result = new UpdateResult();
981
        TaxonNode node = dao.load(taxonNodeUUID);
982
        TeamOrPersonBase<?> agent = (TeamOrPersonBase<?>) agentService.load(agentUUID);
983
        node.addAgentRelation(relationshipType, agent);
984
        try{
985
            dao.merge(node, true);
986
        }catch (Exception e){
987
            result.setError();
988
            result.addException(e);
989
        }
990
        result.setCdmEntity(node);
991
        return result;
992
    }
993

    
994
    @Override
995
    @Transactional(readOnly=false)
996
    public UpdateResult setSecundumForSubtree(SecundumForSubtreeConfigurator config) {
997
        UpdateResult result = new UpdateResult();
998
        IProgressMonitor monitor = config.getMonitor();
999

    
1000
        if (monitor == null){
1001
            monitor = DefaultProgressMonitor.NewInstance();
1002
        }
1003
        TaxonNode subTree = load(config.getSubtreeUuid());
1004
        TreeIndex subTreeIndex = null;
1005
        Reference newSec = null;
1006
        if (config.getNewSecundum() != null){
1007
            newSec = referenceService.load(config.getNewSecundum().getUuid());
1008
        }
1009

    
1010
        if (config.getSubtreeUuid() == null){
1011
            result.setError();
1012
            result.addException(new NullPointerException("No subtree given"));
1013
            monitor.done();
1014
            return result;
1015
        }
1016

    
1017
        if (subTree == null){
1018
            result.setError();
1019
            result.addException(new NullPointerException("Subtree does not exist"));
1020
            monitor.done();
1021
            return result;
1022
        }else{
1023
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
1024
            int count = config.isIncludeAcceptedTaxa() ? dao.countSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail()):0;
1025
            count += config.isIncludeSynonyms() ? dao.countSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail()) :0;
1026
            monitor.beginTask("Update Secundum Reference", count);
1027
        }
1028

    
1029
        //Reference ref = config.getNewSecundum();
1030
        if (config.isIncludeAcceptedTaxa()){
1031
            monitor.subTask("Update Accepted Taxa");
1032

    
1033
            Set<TaxonBase> updatedTaxa = dao.setSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail(), monitor);
1034
            result.addUpdatedObjects(updatedTaxa);
1035
        }
1036
        if (config.isIncludeSynonyms()){
1037
           monitor.subTask("Update Synonyms");
1038
           Set<TaxonBase> updatedSynonyms = dao.setSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail(), monitor);
1039
           result.addUpdatedObjects(updatedSynonyms);
1040
        }
1041

    
1042
        monitor.done();
1043
        return result;
1044
    }
1045

    
1046
    @Override
1047
    @Transactional(readOnly=false)
1048
    public UpdateResult setPublishForSubtree(PublishForSubtreeConfigurator config){
1049
        UpdateResult result = new UpdateResult();
1050
        IProgressMonitor monitor = config.getMonitor();
1051
        if (monitor == null){
1052
            monitor = DefaultProgressMonitor.NewInstance();
1053
        }
1054
        TreeIndex subTreeIndex = null;
1055

    
1056
        if (config.getSubtreeUuid() == null){
1057
            result.setError();
1058
            result.addException(new NullPointerException("No subtree given"));
1059
            monitor.done();
1060
            return result;
1061
        }
1062
        TaxonNode subTree = find(config.getSubtreeUuid());
1063
        boolean includeAcceptedTaxa = config.isIncludeAcceptedTaxa();
1064
        boolean publish = config.isPublish();
1065
        boolean includeSynonyms = config.isIncludeSynonyms();
1066
        boolean includeSharedTaxa = config.isIncludeSharedTaxa();
1067
        boolean includeHybrids = config.isIncludeHybrids();
1068
        boolean includeRelatedTaxa = config.isIncludeProParteSynonyms() || config.isIncludeMisapplications();
1069
        if (subTree == null){
1070
            result.setError();
1071
            result.addException(new NullPointerException("Subtree does not exist"));
1072
            monitor.done();
1073
            return result;
1074
        }else{
1075
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
1076
            int count = includeAcceptedTaxa ? dao.countPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa, includeHybrids):0;
1077
            count += includeSynonyms ? dao.countPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa, includeHybrids):0;
1078
            count += includeRelatedTaxa ? dao.countPublishForSubtreeRelatedTaxa(subTreeIndex, publish, includeSharedTaxa, includeHybrids):0;
1079
            monitor.beginTask("Update publish flag", count);
1080
        }
1081

    
1082

    
1083
        if (includeAcceptedTaxa){
1084
            monitor.subTask("Update Accepted Taxa");
1085
            @SuppressWarnings("rawtypes")
1086
            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa, includeHybrids, monitor);
1087
            result.addUpdatedObjects(updatedTaxa);
1088
        }
1089
        if (includeSynonyms){
1090
            monitor.subTask("Update Synonyms");
1091
            @SuppressWarnings("rawtypes")
1092
            Set<TaxonBase> updatedSynonyms = dao.setPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa, includeHybrids, monitor);
1093
            result.addUpdatedObjects(updatedSynonyms);
1094
        }
1095
        if (includeRelatedTaxa){
1096
            monitor.subTask("Update Related Taxa");
1097
            Set<UUID> relationTypes = new HashSet<>();
1098
            if (config.isIncludeMisapplications()){
1099
                relationTypes.addAll(TaxonRelationshipType.misappliedNameUuids());
1100
            }
1101
            if (config.isIncludeProParteSynonyms()){
1102
                relationTypes.addAll(TaxonRelationshipType.proParteOrPartialSynonymUuids());
1103
            }
1104
            @SuppressWarnings("rawtypes")
1105
            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeRelatedTaxa(subTreeIndex, publish,
1106
                    relationTypes, includeSharedTaxa, includeHybrids, monitor);
1107
            result.addUpdatedObjects(updatedTaxa);
1108
        }
1109

    
1110
        monitor.done();
1111
        return result;
1112
    }
1113

    
1114
    @Override
1115
    public long count(TaxonNodeFilter filter){
1116
        return nodeFilterDao.count(filter);
1117
    }
1118

    
1119
    @Override
1120
    public List<UUID> uuidList(TaxonNodeFilter filter){
1121
        return nodeFilterDao.listUuids(filter);
1122
    }
1123

    
1124
    @Override
1125
    public List<Integer> idList(TaxonNodeFilter filter){
1126
        return nodeFilterDao.idList(filter);
1127
    }
1128

    
1129
    @Override
1130
    public TaxonNodeDto findCommonParentDto(Collection<TaxonNodeDto> nodes) {
1131
        TaxonNodeDto commonParent = null;
1132
        List<String> treePath = null;
1133
        for (TaxonNodeDto nodeDto : nodes) {
1134
            String nodeTreeIndex = nodeDto.getTreeIndex();
1135
            nodeTreeIndex = nodeTreeIndex.replaceFirst("#", "");
1136
            String[] split = nodeTreeIndex.split("#");
1137
            if(treePath == null){
1138
                treePath = Arrays.asList(split);
1139
            }
1140
            else{
1141
                List<String> match = new ArrayList<>();
1142
                for(int i=0;i<treePath.size();i++){
1143
                    if(i>=split.length){
1144
                        //current tree index is shorter so break
1145
                        break;
1146
                    }
1147
                    else if(split[i].equals(treePath.get(i))){
1148
                        //match found
1149
                        match.add(treePath.get(i));
1150
                    }
1151
                    else{
1152
                        //first mismatch found
1153
                        break;
1154
                    }
1155
                }
1156
                treePath = match;
1157
                if(treePath.isEmpty()){
1158
                    //no common parent found for at least two nodes
1159
                    //-> they belong to a different classification
1160
                    break;
1161
                }
1162
            }
1163
        }
1164
        if(treePath!=null && !treePath.isEmpty()) {
1165
            //get last index
1166
            int nodeId = Integer.parseInt(treePath.get(treePath.size()-1));
1167
            TaxonNode taxonNode = dao.load(nodeId, null);
1168
            commonParent = new TaxonNodeDto(taxonNode);
1169
        }
1170
        return commonParent;
1171
    }
1172

    
1173
    @Override
1174
    public List<TaxonDistributionDTO> getTaxonDistributionDTO(List<UUID> nodeUuids, List<String> propertyPaths, Authentication authentication, boolean openChildren){
1175
        Set<TaxonNode> nodes = new HashSet<>();
1176
        if (openChildren){
1177
            List<TaxonNode> parentNodes = load(nodeUuids, propertyPaths);
1178
            for (TaxonNode node: parentNodes){
1179
                nodes.addAll(listChildrenOf(node, null, null, true, true, propertyPaths));
1180
            }
1181
            nodes.addAll(parentNodes);
1182

    
1183
        }
1184
        List<TaxonDistributionDTO> result = new ArrayList<>();
1185
        boolean hasPermission = false;
1186
        //TaxonDescription instance = TaxonDescription.NewInstance();
1187
        //hasPermission = permissionEvaluator.hasPermission(authentication, instance, Operation.UPDATE);
1188
        for(TaxonNode node:nodes){
1189
            if (authentication != null ) {
1190
                hasPermission = permissionEvaluator.hasPermission(authentication, node, Operation.UPDATE);
1191
            }else {
1192
                hasPermission = true;
1193
            }
1194
            if (node.getTaxon() != null && hasPermission){
1195
                try{
1196
                    TaxonDistributionDTO dto = new TaxonDistributionDTO(node);
1197
                    result.add(dto);
1198
                }catch(Exception e){
1199
                    logger.error(e.getMessage(), e);
1200
                }
1201
            }
1202
        }
1203
//        result.sort(new TaxonDistributionDTOComparator());
1204
        return result;
1205
    }
1206

    
1207
    @Override
1208
    public <S extends TaxonNode> Pager<S> page(Class<S> clazz, List<Restriction<?>> restrictions, Integer pageSize,
1209
            Integer pageIndex, List<OrderHint> orderHints, List<String> propertyPaths) {
1210
        return page(clazz, restrictions, pageSize, pageIndex, orderHints, propertyPaths, INCLUDE_UNPUBLISHED);
1211
    }
1212

    
1213
    @Override
1214
    public <S extends TaxonNode> Pager<S> page(Class<S> clazz, List<Restriction<?>> restrictions, Integer pageSize,
1215
            Integer pageIndex, List<OrderHint> orderHints, List<String> propertyPaths, boolean includeUnpublished) {
1216

    
1217
        List<S> records;
1218
        long resultSize = dao.count(clazz, restrictions);
1219
        if(AbstractPagerImpl.hasResultsInRange(resultSize, pageIndex, pageSize)){
1220
            records = dao.list(clazz, restrictions, pageSize, pageIndex, orderHints, propertyPaths, includeUnpublished);
1221
        } else {
1222
            records = new ArrayList<>();
1223
        }
1224
        Pager<S> pager = new DefaultPagerImpl<>(pageIndex, resultSize, pageSize, records);
1225
        return pager;
1226
    }
1227

    
1228
//    @Override
1229
//    public List<TaxonDistributionDTO> getTaxonDistributionDTOForSubtree(UUID parentNodeUuid,
1230
//            List<String> propertyPaths, boolean openChildren) {
1231
//        return getTaxonDistributionDTOForSubtree(parentNodeUuid, propertyPaths, null, openChildren);
1232
//    }
1233

    
1234
    @Override
1235
    public List<TaxonDistributionDTO> getTaxonDistributionDTO(List<UUID> nodeUuids,
1236
            List<String> propertyPaths, boolean openChildren) {
1237
        return getTaxonDistributionDTO(nodeUuids, propertyPaths, null, openChildren);
1238
    }
1239
}
(90-90/100)