Project

General

Profile

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

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

    
12
import java.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.RemotingProgressMonitor;
41
import eu.etaxonomy.cdm.common.monitor.RemotingProgressMonitorThread;
42
import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
43
import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
44
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
45
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
46
import eu.etaxonomy.cdm.model.common.CdmBase;
47
import eu.etaxonomy.cdm.model.common.DefinedTerm;
48
import eu.etaxonomy.cdm.model.common.TreeIndex;
49
import eu.etaxonomy.cdm.model.description.TaxonDescription;
50
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
51
import eu.etaxonomy.cdm.model.name.HybridRelationship;
52
import eu.etaxonomy.cdm.model.name.TaxonName;
53
import eu.etaxonomy.cdm.model.reference.Reference;
54
import eu.etaxonomy.cdm.model.taxon.Classification;
55
import eu.etaxonomy.cdm.model.taxon.HomotypicGroupTaxonComparator;
56
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
57
import eu.etaxonomy.cdm.model.taxon.Synonym;
58
import eu.etaxonomy.cdm.model.taxon.SynonymType;
59
import eu.etaxonomy.cdm.model.taxon.Taxon;
60
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
61
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
62
import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
63
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
64
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
65
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
66
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeFilterDao;
67
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
68
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
69

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

    
79
    @Autowired
80
    private IBeanInitializer defaultBeanInitializer;
81

    
82
    @Autowired
83
    private ITaxonService taxonService;
84

    
85
    @Autowired
86
    private IAgentService agentService;
87

    
88
    @Autowired
89
    private INameService nameService;
90

    
91
    @Autowired
92
    private IReferenceService refService;
93

    
94
    @Autowired
95
    private ITaxonNodeFilterDao nodeFilterDao;
96

    
97
    @Autowired
98
    IProgressMonitorService progressMonitorService;
99

    
100

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

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

    
113
        HHH_9751_Util.removeAllNull(childNodes);
114

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

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

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

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

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

    
158

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

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

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

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

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

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

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

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

    
208
            allRecords.addAll(synList);
209
        }
210

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

    
214
        TaxonName parentName = null;
215

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

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

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

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

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

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

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

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

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

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

    
308
            }
309

    
310
            newAcceptedTaxon.addSynonym(synonym, srt);
311

    
312

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

    
317
        }
318

    
319

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

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

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

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

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

    
355

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

    
367
        taxonService.saveOrUpdate(newAcceptedTaxon);
368

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

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

    
377

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

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

    
389
        result.addUpdatedObject(newAcceptedTaxon);
390

    
391

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

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

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

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

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

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

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

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

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

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

    
487
            		}
488
            	}
489

    
490
	            classification = taxonNode.getClassification();
491

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

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

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

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

    
513
		            	}
514
	            	}
515
            		classification = null;
516

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

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

    
536
	            }
537

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

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

    
558

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

    
569

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

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

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

    
594
        }
595

    
596

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

    
602

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

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

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

    
634
    	result.addUpdatedObject(parent);
635

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

    
662

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

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

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

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

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

    
702

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

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

    
711
        return result;
712
    }
713

    
714

    
715

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

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

    
732

    
733
        List<TaxonNodeAgentRelation> records = null;
734

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

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

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

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

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

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

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

    
807
    }
808

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

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

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

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

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

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

    
877

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

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

    
910

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

    
926

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

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

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

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

    
959
}
(98-98/105)