Project

General

Profile

Download (48.8 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.taxon.ITaxonNodeDao;
81
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeFilterDao;
82
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
83
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
84
import eu.etaxonomy.cdm.persistence.permission.ICdmPermissionEvaluator;
85
import eu.etaxonomy.cdm.persistence.query.OrderHint;
86

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

    
98
    @Autowired
99
    private IBeanInitializer defaultBeanInitializer;
100

    
101
    @Autowired
102
    private ITaxonService taxonService;
103

    
104
    @Autowired
105
    private IReferenceService referenceService;
106

    
107
    @Autowired
108
    private IDescriptiveDataSetService dataSetService;
109

    
110
    @Autowired
111
    private IAgentService agentService;
112

    
113
    @Autowired
114
    private INameService nameService;
115

    
116
    @Autowired
117
    private IReferenceService refService;
118

    
119
    @Autowired
120
    private ITaxonNodeFilterDao nodeFilterDao;
121

    
122
    @Autowired
123
    IProgressMonitorService progressMonitorService;
124

    
125
    @Autowired
126
    private ICdmPermissionEvaluator permissionEvaluator;
127

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

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

    
148
        HHH_9751_Util.removeAllNull(childNodes);
149

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

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

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

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

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

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

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

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

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

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

    
211
        TaxonNode parentNode = dao.load(taxonNodeUuid);
212

    
213
        List<CdmBase> allRecords = new ArrayList<>();
214

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

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

    
225
            allRecords.addAll(synList);
226
        }
227

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

    
231
        TaxonName parentName = null;
232

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

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

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

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

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

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

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

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

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

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

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

    
340
            }
341

    
342
            newAcceptedTaxon.addSynonym(synonym, srt);
343

    
344

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

    
349
        }
350

    
351

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

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

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

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

    
381
            fromTaxon.removeTaxonRelation(taxonRelationship);
382
            toTaxon.removeTaxonRelation(taxonRelationship);
383
            taxonRelationship.setToTaxon(null);
384
            taxonRelationship.setFromTaxon(null);
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
            if (setNameInSource) {
394
                for (DescriptionElementBase element: description.getElements()){
395
                    for (DescriptionElementSource source: element.getSources()){
396
                        if (source.getNameUsedInSource() == null){
397
                            source.setNameUsedInSource(newSynonymName);
398
                        }
399
                    }
400
                }
401
            }
402
            //oldTaxon.removeDescription(description, false);
403
            newAcceptedTaxon.addDescription(description);
404
        }
405
        oldTaxon.clearDescriptions();
406

    
407
        taxonService.saveOrUpdate(newAcceptedTaxon);
408

    
409
        taxonService.saveOrUpdate(oldTaxon);
410
        taxonService.getSession().flush();
411

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

    
417

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

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

    
429
        result.addUpdatedObject(newAcceptedTaxon);
430

    
431

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

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

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

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

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

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

    
485
        for (TaxonNode treeNode:taxonNodes){
486
        	if (treeNode != null){
487

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

    
522
            		} else {
523
            			//move the children to the parent
524

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

    
529
            		}
530
            	}
531

    
532
	            classification = taxonNode.getClassification();
533

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

    
541
	            	//node is rootNode
542
	            	if (taxon != null){
543

    
544
	            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
545
	            		    taxonService.saveOrUpdate(taxon);
546
	            		    saveOrUpdate(taxonNode);
547

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

    
556
		            	}
557
	            	}
558
            		classification = null;
559

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

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

    
579
	            }
580

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

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

    
601

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

    
612

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

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

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

    
637
        }
638

    
639

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

    
645

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

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

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

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

    
685
    	result.addUpdatedObject(parent);
686

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

    
713

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

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

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

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

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

    
753
        taxonNode = newParent.addChildNode(taxonNode, sortIndex, taxonNode.getReference(),  taxonNode.getMicroReference());
754
        result.addUpdatedObject(taxonNode);
755

    
756
        return result;
757
    }
758

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

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

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

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

    
792
        monitor.done();
793
        return result;
794
    }
795

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

    
800

    
801
        List<TaxonNodeAgentRelation> records = null;
802

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

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

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

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

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

    
845
       Taxon newTaxon = Taxon.NewInstance(name, sec);
846
//       UUID taxonUuid = taxonService.saveOrUpdate(newTaxon);
847
//       newTaxon = (Taxon) taxonService.load(taxonUuid);
848

    
849
       TaxonNode parent = dao.load(parentNodeUuid);
850
       TaxonNode child = null;
851
       Reference ref = null;
852
       if (source != null){
853
           ref = referenceService.load(source.getCitation().getUuid());
854
       }
855

    
856
       try{
857
           child = parent.addChildTaxon(newTaxon, source);
858
           child.setStatus(status);
859

    
860
           if (statusNote != null){
861
               child.getStatusNote().putAll(statusNote);
862
           }
863

    
864
        }catch(Exception e){
865
            result.addException(e);
866
            result.setError();
867
            return result;
868
        }
869
        child = dao.save(child);
870

    
871
        result.addUpdatedObject(parent);
872
        if (child != null){
873
            result.setCdmEntity(child);
874
        }
875
        return result;
876
    }
877

    
878
    @Override
879
    @Transactional
880
    public UpdateResult saveNewTaxonNode(TaxonNode newTaxonNode){
881
        UpdateResult result = new UpdateResult();
882
        UUID parentUuid = newTaxonNode.getParent().getUuid();
883
        Taxon taxon = null;
884

    
885
        if (newTaxonNode.getTaxon().isPersited()){
886
            taxon = (Taxon)taxonService.load(newTaxonNode.getTaxon().getUuid());
887
        }else if (newTaxonNode.getTaxon().getName().isPersited()){
888
            TaxonName name = nameService.load(newTaxonNode.getTaxon().getName().getUuid());
889
            taxon = newTaxonNode.getTaxon();
890
            taxon.setName(name);
891
        }else{
892
            //taxon and name is not persisted, persist possible related names
893
            for (HybridRelationship rel : newTaxonNode.getTaxon().getName().getHybridChildRelations()){
894
                if (!rel.getHybridName().isPersited()) {
895
                    nameService.save(rel.getHybridName());
896
                }
897
                if (!rel.getParentName().isPersited()) {
898
                    nameService.save(rel.getParentName());
899
                }
900
            }
901
        }
902
        if (taxon == null){
903
            taxon = newTaxonNode.getTaxon();
904
        }
905
        taxon.removeTaxonNode(newTaxonNode);
906

    
907
        if (taxon.getSec() != null && taxon.getSec().isPersited()){
908
            Reference sec = referenceService.load(taxon.getSec().getUuid());
909
            taxon.setSec(sec);
910
        }
911
        if (!taxon.isPersited()){
912
            MergeResult<TaxonBase> mergeResult = taxonService.merge(taxon, true);
913
            taxon = (Taxon) mergeResult.getMergedEntity();
914

    
915
        }
916

    
917
        TaxonNode parent = dao.load(parentUuid);
918
        TaxonNode child = null;
919
        try{
920
            child = parent.addChildTaxon(taxon, newTaxonNode.getReference(), newTaxonNode.getMicroReference());
921
        }catch(Exception e){
922
            result.addException(e);
923
            result.setError();
924
            return result;
925
        }
926

    
927
        //TODO can't we work with clone method here?
928
        child.setStatus(newTaxonNode.getStatus());
929
        for (TaxonNodeAgentRelation agentRel :newTaxonNode.getAgentRelations()){
930
            child.addAgentRelation(agentRel.getType(), agentRel.getAgent());
931
        }
932
        for (Entry<Language, LanguageString> entry: newTaxonNode.getStatusNote().entrySet()){
933
            child.putStatusNote(entry.getKey(), entry.getValue().getText());
934
        }
935

    
936
        newTaxonNode = null;
937
        MergeResult<TaxonNode> mergeNode = dao.merge(child,true);
938
        child = mergeNode.getMergedEntity();
939
        result.addUpdatedObject(child.getParent());
940
        result.setCdmEntity(child);
941
        return result;
942
    }
943

    
944
    @Override
945
    @Transactional
946
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, UUID taxonUuid, UUID refUuid, String microref){
947
        UpdateResult result = new UpdateResult();
948
        TaxonNode parent = dao.load(parentNodeUuid);
949
        Taxon taxon = (Taxon) taxonService.load(taxonUuid);
950
        TaxonNode child = null;
951
        try{
952
            child = parent.addChildTaxon(taxon, parent.getReference(), parent.getMicroReference());
953
        }catch(Exception e){
954
            result.addException(e);
955
            result.setError();
956
            return result;
957
        }
958

    
959
        result.addUpdatedObject(parent);
960
        if (child != null){
961
            result.setCdmEntity(child);
962
        }
963
        return result;
964
    }
965

    
966
    @Override
967
    @Transactional
968
    public UpdateResult addTaxonNodeAgentRelation(UUID taxonNodeUUID, UUID agentUUID, DefinedTerm relationshipType){
969
        UpdateResult result = new UpdateResult();
970
        TaxonNode node = dao.load(taxonNodeUUID);
971
        TeamOrPersonBase<?> agent = (TeamOrPersonBase<?>) agentService.load(agentUUID);
972
        node.addAgentRelation(relationshipType, agent);
973
        try{
974
            dao.merge(node, true);
975
        }catch (Exception e){
976
            result.setError();
977
            result.addException(e);
978
        }
979
        result.setCdmEntity(node);
980
        return result;
981
    }
982

    
983
    @Override
984
    @Transactional(readOnly=false)
985
    public UpdateResult setSecundumForSubtree(SecundumForSubtreeConfigurator config) {
986
        UpdateResult result = new UpdateResult();
987
        IProgressMonitor monitor = config.getMonitor();
988

    
989
        if (monitor == null){
990
            monitor = DefaultProgressMonitor.NewInstance();
991
        }
992
        TaxonNode subTree = load(config.getSubtreeUuid());
993
        TreeIndex subTreeIndex = null;
994
        Reference newSec = null;
995
        if (config.getNewSecundum() != null){
996
            newSec = refService.load(config.getNewSecundum().getUuid());
997
        }
998

    
999
        if (config.getSubtreeUuid() == null){
1000
            result.setError();
1001
            result.addException(new NullPointerException("No subtree given"));
1002
            monitor.done();
1003
            return result;
1004
        }
1005

    
1006
        if (subTree == null){
1007
            result.setError();
1008
            result.addException(new NullPointerException("Subtree does not exist"));
1009
            monitor.done();
1010
            return result;
1011
        }else{
1012
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
1013
            int count = config.isIncludeAcceptedTaxa() ? dao.countSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail()):0;
1014
            count += config.isIncludeSynonyms() ? dao.countSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail()) :0;
1015
            monitor.beginTask("Update Secundum Reference", count);
1016
        }
1017

    
1018
        //Reference ref = config.getNewSecundum();
1019
        if (config.isIncludeAcceptedTaxa()){
1020
            monitor.subTask("Update Accepted Taxa");
1021

    
1022
            Set<TaxonBase> updatedTaxa = dao.setSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail(), monitor);
1023
            result.addUpdatedObjects(updatedTaxa);
1024
        }
1025
        if (config.isIncludeSynonyms()){
1026
           monitor.subTask("Update Synonyms");
1027
           Set<TaxonBase> updatedSynonyms = dao.setSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail(), monitor);
1028
           result.addUpdatedObjects(updatedSynonyms);
1029
        }
1030

    
1031
        monitor.done();
1032
        return result;
1033
    }
1034

    
1035
    @Override
1036
    @Transactional(readOnly=false)
1037
    public UpdateResult setPublishForSubtree(PublishForSubtreeConfigurator config){
1038
        UpdateResult result = new UpdateResult();
1039
        IProgressMonitor monitor = config.getMonitor();
1040
        if (monitor == null){
1041
            monitor = DefaultProgressMonitor.NewInstance();
1042
        }
1043
        TreeIndex subTreeIndex = null;
1044

    
1045
        if (config.getSubtreeUuid() == null){
1046
            result.setError();
1047
            result.addException(new NullPointerException("No subtree given"));
1048
            monitor.done();
1049
            return result;
1050
        }
1051
        TaxonNode subTree = find(config.getSubtreeUuid());
1052
        boolean includeAcceptedTaxa = config.isIncludeAcceptedTaxa();
1053
        boolean publish = config.isPublish();
1054
        boolean includeSynonyms = config.isIncludeSynonyms();
1055
        boolean includeSharedTaxa = config.isIncludeSharedTaxa();
1056
        boolean includeHybrids = config.isIncludeHybrids();
1057
        boolean includeRelatedTaxa = config.isIncludeProParteSynonyms() || config.isIncludeMisapplications();
1058
        if (subTree == null){
1059
            result.setError();
1060
            result.addException(new NullPointerException("Subtree does not exist"));
1061
            monitor.done();
1062
            return result;
1063
        }else{
1064
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
1065
            int count = includeAcceptedTaxa ? dao.countPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa, includeHybrids):0;
1066
            count += includeSynonyms ? dao.countPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa, includeHybrids):0;
1067
            count += includeRelatedTaxa ? dao.countPublishForSubtreeRelatedTaxa(subTreeIndex, publish, includeSharedTaxa, includeHybrids):0;
1068
            monitor.beginTask("Update publish flag", count);
1069
        }
1070

    
1071

    
1072
        if (includeAcceptedTaxa){
1073
            monitor.subTask("Update Accepted Taxa");
1074
            @SuppressWarnings("rawtypes")
1075
            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa, includeHybrids, monitor);
1076
            result.addUpdatedObjects(updatedTaxa);
1077
        }
1078
        if (includeSynonyms){
1079
            monitor.subTask("Update Synonyms");
1080
            @SuppressWarnings("rawtypes")
1081
            Set<TaxonBase> updatedSynonyms = dao.setPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa, includeHybrids, monitor);
1082
            result.addUpdatedObjects(updatedSynonyms);
1083
        }
1084
        if (includeRelatedTaxa){
1085
            monitor.subTask("Update Related Taxa");
1086
            Set<UUID> relationTypes = new HashSet<>();
1087
            if (config.isIncludeMisapplications()){
1088
                relationTypes.addAll(TaxonRelationshipType.misappliedNameUuids());
1089
            }
1090
            if (config.isIncludeProParteSynonyms()){
1091
                relationTypes.addAll(TaxonRelationshipType.proParteOrPartialSynonymUuids());
1092
            }
1093
            @SuppressWarnings("rawtypes")
1094
            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeRelatedTaxa(subTreeIndex, publish,
1095
                    relationTypes, includeSharedTaxa, includeHybrids, monitor);
1096
            result.addUpdatedObjects(updatedTaxa);
1097
        }
1098

    
1099
        monitor.done();
1100
        return result;
1101
    }
1102

    
1103
    @Override
1104
    public long count(TaxonNodeFilter filter){
1105
        return nodeFilterDao.count(filter);
1106
    }
1107

    
1108
    @Override
1109
    public List<UUID> uuidList(TaxonNodeFilter filter){
1110
        return nodeFilterDao.listUuids(filter);
1111
    }
1112

    
1113
    @Override
1114
    public List<Integer> idList(TaxonNodeFilter filter){
1115
        return nodeFilterDao.idList(filter);
1116
    }
1117

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

    
1162
    @Override
1163
    public List<TaxonDistributionDTO> getTaxonDistributionDTO(List<UUID> nodeUuids, List<String> propertyPaths, Authentication authentication, boolean openChildren){
1164
        Set<TaxonNode> nodes = new HashSet<>();
1165
        if (openChildren){
1166
            List<TaxonNode> parentNodes = load(nodeUuids, propertyPaths);
1167
            for (TaxonNode node: parentNodes){
1168
                nodes.addAll(listChildrenOf(node, null, null, true, true, propertyPaths));
1169
            }
1170
            nodes.addAll(parentNodes);
1171

    
1172
        }
1173
        List<TaxonDistributionDTO> result = new ArrayList<>();
1174
        boolean hasPermission = false;
1175
        //TaxonDescription instance = TaxonDescription.NewInstance();
1176
        //hasPermission = permissionEvaluator.hasPermission(authentication, instance, Operation.UPDATE);
1177
        for(TaxonNode node:nodes){
1178
            if (authentication != null ) {
1179
                hasPermission = permissionEvaluator.hasPermission(authentication, node, Operation.UPDATE);
1180
            }else {
1181
                hasPermission = true;
1182
            }
1183
            if (node.getTaxon() != null && hasPermission){
1184
                try{
1185
                    TaxonDistributionDTO dto = new TaxonDistributionDTO(node);
1186
                    result.add(dto);
1187
                }catch(Exception e){
1188
                    logger.error(e.getMessage(), e);
1189
                }
1190
            }
1191
        }
1192
//        result.sort(new TaxonDistributionDTOComparator());
1193
        return result;
1194
    }
1195

    
1196
    @Override
1197
    public <S extends TaxonNode> Pager<S> page(Class<S> clazz, List<Restriction<?>> restrictions, Integer pageSize,
1198
            Integer pageIndex, List<OrderHint> orderHints, List<String> propertyPaths) {
1199
        return page(clazz, restrictions, pageSize, pageIndex, orderHints, propertyPaths, INCLUDE_UNPUBLISHED);
1200
    }
1201

    
1202
    @Override
1203
    public <S extends TaxonNode> Pager<S> page(Class<S> clazz, List<Restriction<?>> restrictions, Integer pageSize,
1204
            Integer pageIndex, List<OrderHint> orderHints, List<String> propertyPaths, boolean includeUnpublished) {
1205

    
1206
        List<S> records;
1207
        long resultSize = dao.count(clazz, restrictions);
1208
        if(AbstractPagerImpl.hasResultsInRange(resultSize, pageIndex, pageSize)){
1209
            records = dao.list(clazz, restrictions, pageSize, pageIndex, orderHints, propertyPaths, includeUnpublished);
1210
        } else {
1211
            records = new ArrayList<>();
1212
        }
1213
        Pager<S> pager = new DefaultPagerImpl<>(pageIndex, resultSize, pageSize, records);
1214
        return pager;
1215
    }
1216

    
1217
//    @Override
1218
//    public List<TaxonDistributionDTO> getTaxonDistributionDTOForSubtree(UUID parentNodeUuid,
1219
//            List<String> propertyPaths, boolean openChildren) {
1220
//        return getTaxonDistributionDTOForSubtree(parentNodeUuid, propertyPaths, null, openChildren);
1221
//    }
1222

    
1223
    @Override
1224
    public List<TaxonDistributionDTO> getTaxonDistributionDTO(List<UUID> nodeUuids,
1225
            List<String> propertyPaths, boolean openChildren) {
1226
        return getTaxonDistributionDTO(nodeUuids, propertyPaths, null, openChildren);
1227
    }
1228
}
(90-90/100)