Project

General

Profile

Download (37 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.io.Serializable;
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.Comparator;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.Set;
21
import java.util.UUID;
22

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

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

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

    
78
    @Autowired
79
    private IBeanInitializer defaultBeanInitializer;
80

    
81
    @Autowired
82
    private ITaxonService taxonService;
83

    
84
    @Autowired
85
    private IAgentService agentService;
86

    
87
    @Autowired
88
    private INameService nameService;
89

    
90
    @Autowired
91
    private IReferenceService refService;
92

    
93
    @Autowired
94
    private ITaxonNodeFilterDao nodeFilterDao;
95

    
96
    @Autowired
97
    IProgressMonitorService progressMonitorService;
98

    
99

    
100
    @Override
101
    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
102
            List<String> propertyPaths, boolean recursive, NodeSortMode sortMode) {
103

    
104
        getSession().refresh(taxonNode);
105
        List<TaxonNode> childNodes;
106
        if (recursive == true){
107
        	childNodes  = dao.listChildrenOf(taxonNode, null, null, null, recursive);
108
        }else{
109
        	childNodes = new ArrayList<>(taxonNode.getChildNodes());
110
        }
111

    
112
        HHH_9751_Util.removeAllNull(childNodes);
113

    
114
        if (sortMode != null){
115
            Comparator<TaxonNode> comparator = sortMode.newComparator();
116
        	Collections.sort(childNodes, comparator);
117
        }
118
        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
119
        return childNodes;
120
    }
121

    
122
    /**
123
     * {@inheritDoc}
124
     */
125
    @Override
126
    public UuidAndTitleCache<TaxonNode> getParentUuidAndTitleCache(ITaxonTreeNode child) {
127
        UUID uuid = child.getUuid();
128
        int id = child.getId();
129
        UuidAndTitleCache<TaxonNode> uuidAndTitleCache = new UuidAndTitleCache<>(uuid, id, null);
130
        return getParentUuidAndTitleCache(uuidAndTitleCache);
131
    }
132

    
133
    /**
134
     * {@inheritDoc}
135
     */
136
    @Override
137
    public UuidAndTitleCache<TaxonNode> getParentUuidAndTitleCache(UuidAndTitleCache<TaxonNode> child) {
138
        return dao.getParentUuidAndTitleCache(child);
139
    }
140

    
141
    /**
142
     * {@inheritDoc}
143
     */
144
    @Override
145
    public List<TaxonNodeDto> listChildNodesAsTaxonNodeDto(UuidAndTitleCache<TaxonNode> parent) {
146
        return dao.listChildNodesAsTaxonNodeDto(parent);
147
    }
148

    
149
    /**
150
     * {@inheritDoc}
151
     */
152
    @Override
153
    public List<UuidAndTitleCache<TaxonNode>> listChildNodesAsUuidAndTitleCache(UuidAndTitleCache<TaxonNode> parent) {
154
        return dao.listChildNodesAsUuidAndTitleCache(parent);
155
    }
156

    
157

    
158
    /**
159
     * {@inheritDoc}
160
     */
161
    @Override
162
    public List<UuidAndTitleCache<TaxonNode>> getUuidAndTitleCache(Integer limit, String pattern, UUID classificationUuid) {
163
        return dao.getUuidAndTitleCache(limit, pattern, classificationUuid);
164
    }
165

    
166
    /**
167
     * {@inheritDoc}
168
     */
169
    @Override
170
    public List<TaxonNodeDto> listChildNodesAsTaxonNodeDto(ITaxonTreeNode parent) {
171
        UUID uuid = parent.getUuid();
172
        int id = parent.getId();
173
        UuidAndTitleCache<TaxonNode> uuidAndTitleCache = new UuidAndTitleCache<>(uuid, id, null);
174
        return listChildNodesAsTaxonNodeDto(uuidAndTitleCache);
175
    }
176

    
177
    @Override
178
    public List<UuidAndTitleCache<TaxonNode>> listChildNodesAsUuidAndTitleCache(ITaxonTreeNode parent) {
179
        UUID uuid = parent.getUuid();
180
        int id = parent.getId();
181
        UuidAndTitleCache<TaxonNode> uuidAndTitleCache = new UuidAndTitleCache<>(uuid, id, null);
182
        return listChildNodesAsUuidAndTitleCache(uuidAndTitleCache);
183
    }
184

    
185
    /**
186
     * {@inheritDoc}
187
     */
188
    @Override
189
    public Pager<TaxonNodeDto> pageChildNodesDTOs(UUID taxonNodeUuid, boolean recursive,
190
            boolean doSynonyms, NodeSortMode sortMode,
191
            Integer pageSize, Integer pageIndex) {
192

    
193
        TaxonNode parentNode = dao.load(taxonNodeUuid);
194

    
195
        List<CdmBase> allRecords = new ArrayList<>();
196

    
197
        //acceptedTaxa
198
        List<TaxonNode> childNodes = loadChildNodesOfTaxonNode(parentNode, null, recursive, sortMode);
199
        allRecords.addAll(childNodes);
200

    
201
        //add synonyms if pager is not yet full synonyms
202
        if (doSynonyms){
203
            List<Synonym> synList = new ArrayList<>(parentNode.getTaxon().getSynonyms());
204
            Collections.sort(synList, new HomotypicGroupTaxonComparator(null));
205
            //TODO: test sorting
206

    
207
            allRecords.addAll(synList);
208
        }
209

    
210
        List<TaxonNodeDto> dtos = new ArrayList<>(pageSize==null?25:pageSize);
211
        Long totalCount = Long.valueOf(allRecords.size());
212

    
213
        TaxonName parentName = null;
214

    
215
        for(CdmBase record : PagerUtils.pageList(allRecords, pageIndex, pageSize)) {
216
            if (record.isInstanceOf(TaxonNode.class)){
217
                dtos.add(new TaxonNodeDto(CdmBase.deproxy(record, TaxonNode.class)));
218
            }else if (record.isInstanceOf(Synonym.class)){
219
                Synonym synonym = CdmBase.deproxy(record, Synonym.class);
220
                parentName = parentName == null? parentNode.getTaxon().getName(): parentName;
221
                boolean isHomotypic = synonym.getName().isHomotypic(parentName);
222
                dtos.add(new TaxonNodeDto(synonym, isHomotypic));
223
            }
224
        }
225
        return new DefaultPagerImpl<TaxonNodeDto>(pageIndex, totalCount, pageSize , dtos);
226
    }
227

    
228
    @Override
229
    public TaxonNodeDto parentDto(UUID taxonNodeUuid) {
230
        TaxonNode taxonNode = dao.load(taxonNodeUuid);
231
        if(taxonNode.getParent() != null) {
232
            return new TaxonNodeDto(taxonNode.getParent());
233
        }
234
        return null;
235
    }
236

    
237
    @Override
238
    @Autowired
239
    protected void setDao(ITaxonNodeDao dao) {
240
        this.dao = dao;
241
    }
242

    
243
    @Override
244
    @Transactional(readOnly = false)
245
    public DeleteResult makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode,
246
            SynonymType synonymType, Reference citation, String citationMicroReference)  {
247

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

    
254
        if(oldTaxonNode.equals(newAcceptedTaxonNode)){
255
            throw new IllegalArgumentException("Taxon can not be made synonym of its own.");
256
        }
257

    
258
        Classification classification = oldTaxonNode.getClassification();
259
        Taxon oldTaxon = HibernateProxyHelper.deproxy(oldTaxonNode.getTaxon());
260
        Taxon newAcceptedTaxon = (Taxon)this.taxonService.find(newAcceptedTaxonNode.getTaxon().getUuid());
261
        newAcceptedTaxon = HibernateProxyHelper.deproxy(newAcceptedTaxon);
262
        // Move oldTaxon to newTaxon
263
        //TaxonName synonymName = oldTaxon.getName();
264
        TaxonName newSynonymName = CdmBase.deproxy(oldTaxon.getName());
265
        HomotypicalGroup group = CdmBase.deproxy(newSynonymName.getHomotypicalGroup());
266
        if (synonymType == null){
267
            if (newSynonymName.isHomotypic(newAcceptedTaxon.getName())){
268
                synonymType = SynonymType.HOMOTYPIC_SYNONYM_OF();
269
            }else{
270
                synonymType = SynonymType.HETEROTYPIC_SYNONYM_OF();
271
            }
272
        }
273

    
274
        //set homotypic group
275
        TaxonName newAcceptedTaxonName = HibernateProxyHelper.deproxy(newAcceptedTaxon.getName(), TaxonName.class);
276
        newAcceptedTaxon.setName(newAcceptedTaxonName);
277
        // Move Synonym Relations to new Taxon
278
        newAcceptedTaxon.addSynonymName(newSynonymName, citation, citationMicroReference, synonymType);
279
         // Move Synonyms to new Taxon
280
        // From ticket 3163 we can move taxon with accepted name having homotypic synonyms
281
        List<Synonym> synonymsInHomotypicalGroup = null;
282

    
283
        //the synonyms of the homotypical group of the old taxon
284
        if (synonymType.equals(SynonymType.HOMOTYPIC_SYNONYM_OF())){
285
        	synonymsInHomotypicalGroup = oldTaxon.getSynonymsInGroup(group);
286
        }
287

    
288
        Set<Synonym> syns = new HashSet<>(oldTaxon.getSynonyms());
289
        for(Synonym synonym : syns){
290
            SynonymType srt;
291
            if(synonym.getHomotypicGroup()!= null
292
                    && synonym.getHomotypicGroup().equals(newAcceptedTaxonName.getHomotypicalGroup())) {
293
                srt = SynonymType.HOMOTYPIC_SYNONYM_OF();
294
            } else if(synonym.getType() != null && synonym.getType().equals(SynonymType.HOMOTYPIC_SYNONYM_OF())) {
295
            	if (synonymType.equals(SynonymType.HOMOTYPIC_SYNONYM_OF())){
296
            		srt = SynonymType.HOMOTYPIC_SYNONYM_OF();
297
            	} else{
298
            		srt = SynonymType.HETEROTYPIC_SYNONYM_OF();
299
            	}
300
            } else {
301
                if (synonymsInHomotypicalGroup != null && synonymsInHomotypicalGroup.contains(synonym)){
302
                    srt = SynonymType.HOMOTYPIC_SYNONYM_OF();
303
                }else{
304
                    srt = synonym.getType();
305
                }
306

    
307
            }
308

    
309
            newAcceptedTaxon.addSynonym(synonym, srt);
310

    
311

    
312
            /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymType.HETEROTYPIC_SYNONYM_OF())){
313
            	homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
314
            }*/
315

    
316
        }
317

    
318

    
319
        // CHILD NODES
320
        if(oldTaxonNode.getChildNodes() != null && oldTaxonNode.getChildNodes().size() != 0){
321
        	List<TaxonNode> childNodes = new ArrayList<>();
322
        	for (TaxonNode childNode : oldTaxonNode.getChildNodes()){
323
        		childNodes.add(childNode);
324
        	}
325
            for(TaxonNode childNode :childNodes){
326
                newAcceptedTaxonNode.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference()); // childNode.getSynonymToBeUsed()
327
            }
328
        }
329

    
330
        //Move Taxon RelationShips to new Taxon
331
        for(TaxonRelationship taxonRelationship : oldTaxon.getTaxonRelations()){
332
            Taxon fromTaxon = HibernateProxyHelper.deproxy(taxonRelationship.getFromTaxon());
333
            Taxon toTaxon = HibernateProxyHelper.deproxy(taxonRelationship.getToTaxon());
334
            if (fromTaxon == oldTaxon){
335
                newAcceptedTaxon.addTaxonRelation(taxonRelationship.getToTaxon(), taxonRelationship.getType(),
336
                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
337

    
338
            }else if(toTaxon == oldTaxon){
339
               fromTaxon.addTaxonRelation(newAcceptedTaxon, taxonRelationship.getType(),
340
                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
341
               taxonService.saveOrUpdate(fromTaxon);
342

    
343
            }else{
344
                logger.warn("Taxon is not part of its own Taxonrelationship");
345
            }
346
            // Remove old relationships
347

    
348
            fromTaxon.removeTaxonRelation(taxonRelationship);
349
            toTaxon.removeTaxonRelation(taxonRelationship);
350
            taxonRelationship.setToTaxon(null);
351
            taxonRelationship.setFromTaxon(null);
352
        }
353

    
354

    
355
        //Move descriptions to new taxon
356
        List<TaxonDescription> descriptions = new ArrayList<TaxonDescription>( oldTaxon.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())
357
        for(TaxonDescription description : descriptions){
358
            String message = "Description copied from former accepted taxon: %s (Old title: %s)";
359
            message = String.format(message, oldTaxon.getTitleCache(), description.getTitleCache());
360
            description.setTitleCache(message, true);
361
            //oldTaxon.removeDescription(description, false);
362
            newAcceptedTaxon.addDescription(description);
363
        }
364
        oldTaxon.clearDescriptions();
365

    
366
        taxonService.saveOrUpdate(newAcceptedTaxon);
367

    
368
        taxonService.saveOrUpdate(oldTaxon);
369
        taxonService.getSession().flush();
370

    
371
        TaxonDeletionConfigurator conf = new TaxonDeletionConfigurator();
372
        conf.setDeleteSynonymsIfPossible(false);
373
        conf.setDeleteNameIfPossible(false);
374
        DeleteResult result = taxonService.isDeletable(oldTaxon.getUuid(), conf);
375

    
376

    
377
        if (result.isOk()){
378
        	 result = taxonService.deleteTaxon(oldTaxon.getUuid(), conf, classification.getUuid());
379

    
380
        }else{
381
        	result.setStatus(Status.OK);
382
        	TaxonNodeDeletionConfigurator config = new TaxonNodeDeletionConfigurator();
383
        	config.setDeleteElement(false);
384
        	conf.setTaxonNodeConfig(config);
385
        	result.includeResult(deleteTaxonNode(oldTaxonNode, conf));
386
        }
387

    
388
        result.addUpdatedObject(newAcceptedTaxon);
389

    
390

    
391
        //oldTaxonNode.delete();
392
        return result;
393
    }
394
    @Override
395
    @Transactional(readOnly = false)
396
    public UpdateResult makeTaxonNodeSynonymsOfAnotherTaxonNode( Set<UUID> oldTaxonNodeUuids,
397
            UUID newAcceptedTaxonNodeUUIDs,
398
            SynonymType synonymType,
399
            Reference citation,
400
            String citationMicroReference) {
401
    	UpdateResult result = new UpdateResult();
402
    	for (UUID nodeUuid: oldTaxonNodeUuids) {
403
    		result.includeResult(makeTaxonNodeASynonymOfAnotherTaxonNode(nodeUuid, newAcceptedTaxonNodeUUIDs, synonymType, citation, citationMicroReference));
404
    	}
405
    	return result;
406
    }
407

    
408
    @Override
409
    @Transactional(readOnly = false)
410
    public UpdateResult makeTaxonNodeASynonymOfAnotherTaxonNode(UUID oldTaxonNodeUuid,
411
            UUID newAcceptedTaxonNodeUUID,
412
            SynonymType synonymType,
413
            Reference citation,
414
            String citationMicroReference) {
415

    
416
        TaxonNode oldTaxonNode = dao.load(oldTaxonNodeUuid);
417
        TaxonNode oldTaxonParentNode = oldTaxonNode.getParent();
418
        TaxonNode newTaxonNode = dao.load(newAcceptedTaxonNodeUUID);
419

    
420
        UpdateResult result = makeTaxonNodeASynonymOfAnotherTaxonNode(oldTaxonNode,
421
                newTaxonNode,
422
                synonymType,
423
                citation,
424
                citationMicroReference);
425
        result.addUpdatedCdmId(new CdmEntityIdentifier(oldTaxonParentNode.getId(), TaxonNode.class));
426
        result.addUpdatedCdmId(new CdmEntityIdentifier(newTaxonNode.getId(), TaxonNode.class));
427
        result.setCdmEntity(oldTaxonParentNode);
428
        return result;
429
    }
430

    
431
    @Override
432
    @Transactional(readOnly = false)
433
    public DeleteResult deleteTaxonNodes(List<TaxonNode> list, TaxonDeletionConfigurator config) {
434

    
435
        if (config == null){
436
        	config = new TaxonDeletionConfigurator();
437
        }
438
        DeleteResult result = new DeleteResult();
439
        Classification classification = null;
440
        List<TaxonNode> taxonNodes = new ArrayList<>(list);
441

    
442
        for (TaxonNode treeNode:taxonNodes){
443
        	if (treeNode != null){
444

    
445
        		TaxonNode taxonNode;
446
	            taxonNode = HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);
447
	            TaxonNode parent = taxonNode.getParent();
448
	            	//check whether the node has children or the children are already deleted
449
	            if(taxonNode.hasChildNodes()) {
450
            		List<TaxonNode> children = new ArrayList<TaxonNode> ();
451
            		List<TaxonNode> childNodesList = taxonNode.getChildNodes();
452
        			children.addAll(childNodesList);
453
        			//To avoid NPE when child is also in list of taxonNodes, remove it from the list
454
        			Iterator<TaxonNode> it = taxonNodes.iterator();
455
        			for (TaxonNode child: children) {
456
        				while (it.hasNext()) {
457
        					if (it.next().equals(child)) {
458
        						it.remove();
459
        					}
460
        				}
461
        			}
462
        			int compare = config.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling.DELETE);
463
        			boolean childHandling = (compare == 0)? true: false;
464
            		if (childHandling){
465
            			boolean changeDeleteTaxon = false;
466
            			if (!config.getTaxonNodeConfig().isDeleteTaxon()){
467
            				config.getTaxonNodeConfig().setDeleteTaxon(true);
468
            				changeDeleteTaxon = true;
469
            			}
470
            			DeleteResult resultNodes = deleteTaxonNodes(children, config);
471
            			if (!resultNodes.isOk()){
472
                            result.addExceptions(resultNodes.getExceptions());
473
                            result.setStatus(resultNodes.getStatus());
474
                        }
475
            			if (changeDeleteTaxon){
476
            				config.getTaxonNodeConfig().setDeleteTaxon(false);
477
            			}
478

    
479
            		} else {
480
            			//move the children to the parent
481

    
482
            			for (TaxonNode child: childNodesList){
483
            				parent.addChildNode(child, child.getReference(), child.getMicroReference());
484
            			}
485

    
486
            		}
487
            	}
488

    
489
	            classification = taxonNode.getClassification();
490

    
491
	            if (classification.getRootNode().equals(taxonNode)){
492
	            	classification.removeRootNode();
493
	            	classification = null;
494
	            }else if (classification.getChildNodes().contains(taxonNode)){
495
            		Taxon taxon = taxonNode.getTaxon();
496
            		classification.deleteChildNode(taxonNode);
497

    
498
	            	//node is rootNode
499
	            	if (taxon != null){
500

    
501
	            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
502
	            		    taxonService.saveOrUpdate(taxon);
503
	            		    saveOrUpdate(taxonNode);
504

    
505
			            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
506
			            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, classification.getUuid());
507
			            	if (!resultTaxon.isOk()){
508
                                result.addExceptions(resultTaxon.getExceptions());
509
                                result.setStatus(resultTaxon.getStatus());
510
                            }
511

    
512
		            	}
513
	            	}
514
            		classification = null;
515

    
516
	            } else {
517
	            	classification = null;
518
	            	Taxon taxon = taxonNode.getTaxon();
519
	            	taxon = HibernateProxyHelper.deproxy(taxon, Taxon.class);
520
	            	if (taxon != null){
521
	            		taxon.removeTaxonNode(taxonNode);
522
	            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
523
			            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
524
			            	saveOrUpdate(taxonNode);
525
			            	taxonService.saveOrUpdate(taxon);
526
			            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, null);
527

    
528
                            if (!resultTaxon.isOk()){
529
                                result.addExceptions(resultTaxon.getExceptions());
530
                                result.setStatus(resultTaxon.getStatus());
531
                            }
532
		            	}
533
	            	}
534

    
535
	            }
536

    
537
	            result.addUpdatedObject(parent);
538
	            if(result.getCdmEntity() == null){
539
	                result.setCdmEntity(taxonNode);
540
                }
541
	            UUID uuid = dao.delete(taxonNode);
542
	            logger.debug("Deleted node " +uuid.toString());
543

    
544
	        }
545
        }
546
        /*if (classification != null){
547
            result.addUpdatedObject(classification);
548
        	DeleteResult resultClassification = classService.delete(classification);
549
        	 if (!resultClassification.isOk()){
550
                 result.addExceptions(resultClassification.getExceptions());
551
                 result.setStatus(resultClassification.getStatus());
552
             }
553
        }*/
554
        return result;
555
    }
556

    
557

    
558
    @Override
559
    @Transactional(readOnly = false)
560
    public DeleteResult deleteTaxonNodes(Collection<UUID> nodeUuids, TaxonDeletionConfigurator config) {
561
        List<TaxonNode> nodes = new ArrayList<>();
562
        for(UUID nodeUuid : nodeUuids) {
563
            nodes.add(dao.load(nodeUuid));
564
        }
565
        return deleteTaxonNodes(nodes, config);
566
    }
567

    
568

    
569
    @Override
570
    @Transactional(readOnly = false)
571
    public DeleteResult deleteTaxonNode(UUID nodeUUID, TaxonDeletionConfigurator config) {
572

    
573
    	TaxonNode node = HibernateProxyHelper.deproxy(dao.load(nodeUUID), TaxonNode.class);
574
    	return deleteTaxonNode(node, config);
575
    }
576

    
577
    @Override
578
    @Transactional(readOnly = false)
579
    public DeleteResult deleteTaxonNode(TaxonNode node, TaxonDeletionConfigurator config) {
580
        DeleteResult result = new DeleteResult();
581
        if (node == null){
582
            result.setAbort();
583
            result.addException(new Exception("The TaxonNode was already deleted."));
584
            return result;
585
        }
586
        Taxon taxon = null;
587
        try{
588
            taxon = HibernateProxyHelper.deproxy(node.getTaxon());
589
        }catch(NullPointerException e){
590
            result.setAbort();
591
            result.addException(new Exception("The Taxon was already deleted."));
592

    
593
        }
594

    
595

    
596
    	TaxonNode parent = HibernateProxyHelper.deproxy(node.getParent(), TaxonNode.class);
597
    	if (config == null){
598
    		config = new TaxonDeletionConfigurator();
599
    	}
600

    
601

    
602
    	if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.MOVE_TO_PARENT)){
603
    	   Object[] children = node.getChildNodes().toArray();
604
    	   TaxonNode childNode;
605
    	   for (Object child: children){
606
    	       childNode = (TaxonNode) child;
607
    	       parent.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference());
608

    
609
    	   }
610
    	}else{
611
    	    result.includeResult(deleteTaxonNodes(node.getChildNodes(), config));
612
    	}
613

    
614
    	if (taxon != null){
615
        	if (config.getTaxonNodeConfig().isDeleteTaxon() && (config.isDeleteInAllClassifications() || taxon.getTaxonNodes().size() == 1)){
616
        		result = taxonService.deleteTaxon(taxon.getUuid(), config, node.getClassification().getUuid());
617
        		result.addUpdatedObject(parent);
618
        		if (result.isOk()){
619
        			return result;
620
        		}
621
        	} else {
622
        	    result.addUpdatedObject(taxon);
623
        	}
624
    	}
625
    	result.setCdmEntity(node);
626
    	boolean success = true;
627
    	if (taxon != null){
628
    	    success = taxon.removeTaxonNode(node);
629
    	    taxonService.saveOrUpdate(taxon);
630
    	}
631
    	dao.saveOrUpdate(parent);
632

    
633
    	result.addUpdatedObject(parent);
634

    
635
    	if (success){
636
			result.setStatus(Status.OK);
637
			if (parent != null){
638
    			parent = HibernateProxyHelper.deproxy(parent, TaxonNode.class);
639
    			int index = parent.getChildNodes().indexOf(node);
640
    			if (index > -1){
641
    			    parent.removeChild(index);
642
    			}
643
			}
644
    		if (!dao.delete(node, config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)).equals(null)){
645
    		    result.getUpdatedObjects().remove(node);
646
    			result.addDeletedObject(node);
647
    			return result;
648
    		} else {
649
    			result.setError();
650
    			return result;
651
    		}
652
    	}else{
653
    	    if (dao.findByUuid(node.getUuid()) != null){
654
        		result.setError();
655
        		result.addException(new Exception("The node can not be removed from the taxon."));
656
    		}
657
    		return result;
658
    	}
659
    }
660

    
661

    
662
    @Override
663
    public List<TaxonNode> listAllNodesForClassification(Classification classification, Integer start, Integer end) {
664
        return dao.getTaxonOfAcceptedTaxaByClassification(classification, start, end);
665
    }
666

    
667
    @Override
668
    public int countAllNodesForClassification(Classification classification) {
669
        return dao.countTaxonOfAcceptedTaxaByClassification(classification);
670
    }
671

    
672
    @Override
673
    @Transactional
674
    public UpdateResult moveTaxonNode(UUID taxonNodeUuid, UUID targetNodeUuid, int movingType){
675
        TaxonNode taxonNode = HibernateProxyHelper.deproxy(dao.load(taxonNodeUuid), TaxonNode.class);
676
    	TaxonNode targetNode = HibernateProxyHelper.deproxy(dao.load(targetNodeUuid), TaxonNode.class);
677
    	return moveTaxonNode(taxonNode, targetNode, movingType);
678
    }
679

    
680
    @Override
681
    @Transactional
682
    public UpdateResult moveTaxonNode(TaxonNode taxonNode, TaxonNode newParent, int movingType){
683
        UpdateResult result = new UpdateResult();
684

    
685
        TaxonNode parentParent = HibernateProxyHelper.deproxy(newParent.getParent());
686
        TaxonNode oldParent = HibernateProxyHelper.deproxy(taxonNode.getParent());
687
        Integer sortIndex = -1;
688
        if (movingType == 0){
689
            sortIndex = 0;
690
        }else if (movingType == 1){
691
            sortIndex = newParent.getSortIndex();
692
            newParent = parentParent;
693
        } else if (movingType == 2){
694
            sortIndex = newParent.getSortIndex() +1;
695
            newParent = parentParent;
696
        } else{
697
            result.setAbort();
698
            result.addException(new Exception("The moving type "+ movingType +" is not supported."));
699
        }
700

    
701

    
702
        taxonNode = newParent.addChildNode(taxonNode, sortIndex, taxonNode.getReference(),  taxonNode.getMicroReference());
703
        result.addUpdatedObject(newParent);
704
        result.addUpdatedObject(oldParent);
705
        result.setCdmEntity(taxonNode);
706

    
707
        dao.saveOrUpdate(taxonNode);
708
        dao.saveOrUpdate(oldParent);
709

    
710
        return result;
711
    }
712

    
713

    
714

    
715
    @Override
716
    @Transactional
717
    public UpdateResult moveTaxonNodes(Set<UUID> taxonNodeUuids, UUID newParentNodeUuid, int movingType){
718
        UpdateResult result = new UpdateResult();
719
        TaxonNode targetNode = dao.load(newParentNodeUuid);
720
        for (UUID taxonNodeUuid: taxonNodeUuids){
721
            TaxonNode taxonNode = dao.load(taxonNodeUuid);
722
            result.includeResult(moveTaxonNode(taxonNode,targetNode, movingType));
723
        }
724
        return result;
725
    }
726

    
727
    @Override
728
    public Pager<TaxonNodeAgentRelation> pageTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,
729
            UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
730

    
731

    
732
        List<TaxonNodeAgentRelation> records = null;
733

    
734
        long count = dao.countTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid);
735
        if(PagerUtils.hasResultsInRange(count, pageIndex, pageSize)) {
736
            records = dao.listTaxonNodeAgentRelations(taxonUuid, classificationUuid,
737
                    agentUuid, rankUuid, relTypeUuid, PagerUtils.startFor(pageSize, pageIndex), PagerUtils.limitFor(pageSize), propertyPaths);
738
        }
739

    
740
        Pager<TaxonNodeAgentRelation> pager = new DefaultPagerImpl<>(pageIndex, count, pageSize, records);
741
        return pager;
742
    }
743

    
744
    @Override
745
    @Transactional
746
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, Taxon newTaxon, Reference ref, String microref){
747
        UpdateResult result = new UpdateResult();
748
        if (newTaxon.getName().getId() != 0){
749
            TaxonName name = nameService.load(newTaxon.getName().getUuid());
750
            newTaxon.setName(name);
751
        }else{
752
            for (HybridRelationship rel : newTaxon.getName().getHybridChildRelations()){
753
                if (!rel.getHybridName().isPersited()) {
754
                    nameService.save(rel.getHybridName());
755
                }
756
                if (!rel.getParentName().isPersited()) {
757
                    nameService.save(rel.getParentName());
758
                }
759
            }
760
        }
761
        UUID taxonUUID = taxonService.saveOrUpdate(newTaxon);
762
        newTaxon = (Taxon) taxonService.load(taxonUUID);
763

    
764
        TaxonNode parent = dao.load(parentNodeUuid);
765
        TaxonNode child = null;
766
        try{
767
            child = parent.addChildTaxon(newTaxon, parent.getReference(), parent.getMicroReference());
768
        }catch(Exception e){
769
            result.addException(e);
770
            result.setError();
771
            return result;
772
        }
773
//        child = dao.save(child);
774

    
775
        dao.saveOrUpdate(parent);
776
        result.addUpdatedObject(parent);
777
        if (child != null){
778
            result.setCdmEntity(child);
779
        }
780
        return result;
781

    
782
    }
783
    @Override
784
    @Transactional
785
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, UUID taxonUuid, Reference ref, String microref){
786
        UpdateResult result = new UpdateResult();
787
        TaxonNode parent = dao.load(parentNodeUuid);
788
        Taxon taxon = (Taxon) taxonService.load(taxonUuid);
789
        TaxonNode child = null;
790
        try{
791
            child = parent.addChildTaxon(taxon, parent.getReference(), parent.getMicroReference());
792
        }catch(Exception e){
793
            result.addException(e);
794
            result.setError();
795
            return result;
796
        }
797
//        child = dao.save(child);
798

    
799
//        dao.saveOrUpdate(child);
800
        result.addUpdatedObject(parent);
801
        if (child != null){
802
            result.setCdmEntity(child);
803
        }
804
        return result;
805

    
806
    }
807

    
808
    @Override
809
    @Transactional
810
    public UpdateResult addTaxonNodeAgentRelation(UUID taxonNodeUUID, UUID agentUUID, DefinedTerm relationshipType){
811
        UpdateResult result = new UpdateResult();
812
        TaxonNode node = dao.load(taxonNodeUUID);
813
        TeamOrPersonBase<?> agent = (TeamOrPersonBase<?>) agentService.load(agentUUID);
814
        node.addAgentRelation(relationshipType, agent);
815
        try{
816
            dao.merge(node, true);
817
        }catch (Exception e){
818
            result.setError();
819
            result.addException(e);
820
        }
821
        result.setCdmEntity(node);
822
        return result;
823
    }
824

    
825
    @Override
826
    @Transactional(readOnly=false)
827
    public UpdateResult setSecundumForSubtree(SecundumForSubtreeConfigurator config) {
828
        UpdateResult result = new UpdateResult();
829
        IProgressMonitor monitor = config.getMonitor();
830
        if (monitor == null){
831
            monitor = DefaultProgressMonitor.NewInstance();
832
        }
833
        TaxonNode subTree = load(config.getSubtreeUuid());
834
        TreeIndex subTreeIndex = null;
835
        Reference newSec = null;
836
        if (config.getNewSecundum() != null){
837
            newSec = refService.load(config.getNewSecundum().getUuid());
838
        }
839

    
840
        if (config.getSubtreeUuid() == null){
841
            result.setError();
842
            result.addException(new NullPointerException("No subtree given"));
843
            monitor.done();
844
            return result;
845
        }
846

    
847
        if (subTree == null){
848
            result.setError();
849
            result.addException(new NullPointerException("Subtree does not exist"));
850
            monitor.done();
851
            return result;
852
        }else{
853
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
854
            int count = config.isIncludeAcceptedTaxa() ? dao.countSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail()):0;
855
            count += config.isIncludeSynonyms() ? dao.countSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail()) :0;
856
            monitor.beginTask("Update Secundum Reference", count);
857
        }
858

    
859
        //Reference ref = config.getNewSecundum();
860
        if (config.isIncludeAcceptedTaxa()){
861
            monitor.subTask("Update Accepted Taxa");
862

    
863
            Set<TaxonBase> updatedTaxa = dao.setSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail(), monitor);
864
            result.addUpdatedObjects(updatedTaxa);
865
        }
866
        if (config.isIncludeSynonyms()){
867
           monitor.subTask("Update Synonyms");
868
           Set<TaxonBase> updatedSynonyms = dao.setSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail(), monitor);
869
           result.addUpdatedObjects(updatedSynonyms);
870
        }
871

    
872
        monitor.done();
873
        return result;
874
    }
875

    
876

    
877
    /**
878
     * {@inheritDoc}
879
     */
880
    @Override
881
    @Transactional(readOnly=false)
882
    public UpdateResult setPublishForSubtree(UUID subtreeUuid, boolean publish, boolean includeAcceptedTaxa,
883
            boolean includeSynonyms, boolean includeSharedTaxa, IProgressMonitor monitor) {
884
        UpdateResult result = new UpdateResult();
885
        if (monitor == null){
886
            monitor = DefaultProgressMonitor.NewInstance();
887
        }
888
        TreeIndex subTreeIndex = null;
889

    
890
        if (subtreeUuid == null){
891
            result.setError();
892
            result.addException(new NullPointerException("No subtree given"));
893
            monitor.done();
894
            return result;
895
        }
896
        TaxonNode subTree = find(subtreeUuid);
897
        if (subTree == null){
898
            result.setError();
899
            result.addException(new NullPointerException("Subtree does not exist"));
900
            monitor.done();
901
            return result;
902
        }else{
903
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
904
            int count = includeAcceptedTaxa ? dao.countPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa):0;
905
            count += includeSynonyms ? dao.countPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa):0;
906
            monitor.beginTask("Update publish flag", count);
907
        }
908

    
909

    
910
        if (includeAcceptedTaxa){
911
            monitor.subTask("Update Accepted Taxa");
912
            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa, monitor);
913
            result.addUpdatedObjects(updatedTaxa);
914
        }
915
        if (includeSynonyms){
916
            monitor.subTask("Update Synonyms");
917
            Set<TaxonBase> updatedSynonyms = dao.setPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa, monitor);
918
            result.addUpdatedObjects(updatedSynonyms);
919
        }
920
        monitor.done();
921
        return result;
922
    }
923

    
924

    
925
    @Override
926
    public long count(TaxonNodeFilter filter){
927
        return nodeFilterDao.count(filter);
928
    }
929

    
930
    @Override
931
    public List<UUID> uuidList(TaxonNodeFilter filter){
932
        return nodeFilterDao.listUuids(filter);
933
    }
934

    
935
    @Override
936
    public List<Integer> idList(TaxonNodeFilter filter){
937
        return nodeFilterDao.idList(filter);
938
    }
939

    
940
    @Override
941
    @Transactional(readOnly=false)
942
    public UUID monitSetSecundum(final SecundumForSubtreeConfigurator configurator) {
943
        RemotingProgressMonitorThread monitorThread = new RemotingProgressMonitorThread() {
944
            @Override
945
            public Serializable doRun(IRemotingProgressMonitor monitor) {
946
                configurator.setMonitor(monitor);
947
                UpdateResult result = setSecundumForSubtree(configurator);
948
                return result;
949
            }
950
        };
951
        UUID uuid = progressMonitorService.registerNewRemotingMonitor(monitorThread);
952
        monitorThread.setPriority(3);
953
        monitorThread.start();
954
        return uuid;
955
    }
956

    
957
}
(98-98/105)