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
            UUID refUuid, 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 (refUuid != null){
853
           ref = referenceService.load(refUuid);
854
       }
855

    
856
       try{
857
           child = parent.addChildTaxon(newTaxon, ref, microref);
858
           child.setStatus(status);
859
           if (statusNote != null){
860
               child.getStatusNote().putAll(statusNote);
861
           }
862

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

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

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

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

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

    
914
        }
915

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1070

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

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

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

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

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

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

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

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

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

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

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

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

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