Project

General

Profile

Download (35.4 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.TaxonName;
51
import eu.etaxonomy.cdm.model.reference.Reference;
52
import eu.etaxonomy.cdm.model.taxon.Classification;
53
import eu.etaxonomy.cdm.model.taxon.HomotypicGroupTaxonComparator;
54
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
55
import eu.etaxonomy.cdm.model.taxon.Synonym;
56
import eu.etaxonomy.cdm.model.taxon.SynonymType;
57
import eu.etaxonomy.cdm.model.taxon.Taxon;
58
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
59
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
60
import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
61
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
62
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
63
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
64
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeFilterDao;
65
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
66
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
67

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

    
77
    @Autowired
78
    private IBeanInitializer defaultBeanInitializer;
79

    
80
    @Autowired
81
    private ITaxonService taxonService;
82

    
83
    @Autowired
84
    private IAgentService agentService;
85

    
86
    @Autowired
87
    private INameService nameService;
88

    
89
    @Autowired
90
    private IReferenceService refService;
91

    
92
    @Autowired
93
    private ITaxonNodeFilterDao nodeFilterDao;
94

    
95
    @Autowired
96
    IProgressMonitorService progressMonitorService;
97

    
98

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

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

    
111
        HHH_9751_Util.removeAllNull(childNodes);
112

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

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

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

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

    
148
    /**
149
     * {@inheritDoc}
150
     */
151
    @Override
152
    public List<UuidAndTitleCache<TaxonNode>> getUuidAndTitleCache(Integer limit, String pattern, UUID classificationUuid) {
153
        return dao.getUuidAndTitleCache(limit, pattern, classificationUuid);
154
    }
155

    
156
    /**
157
     * {@inheritDoc}
158
     */
159
    @Override
160
    public List<TaxonNodeDto> listChildNodesAsUuidAndTitleCache(ITaxonTreeNode parent) {
161
        UUID uuid = parent.getUuid();
162
        int id = parent.getId();
163
        UuidAndTitleCache<TaxonNode> uuidAndTitleCache = new UuidAndTitleCache<>(uuid, id, null);
164
        return listChildNodesAsUuidAndTitleCache(uuidAndTitleCache);
165
    }
166

    
167
    /**
168
     * {@inheritDoc}
169
     */
170
    @Override
171
    public Pager<TaxonNodeDto> pageChildNodesDTOs(UUID taxonNodeUuid, boolean recursive,
172
            boolean doSynonyms, NodeSortMode sortMode,
173
            Integer pageSize, Integer pageIndex) {
174

    
175
        TaxonNode parentNode = dao.load(taxonNodeUuid);
176

    
177
        List<CdmBase> allRecords = new ArrayList<>();
178

    
179
        //acceptedTaxa
180
        List<TaxonNode> childNodes = loadChildNodesOfTaxonNode(parentNode, null, recursive, sortMode);
181
        allRecords.addAll(childNodes);
182

    
183
        //add synonyms if pager is not yet full synonyms
184
        if (doSynonyms){
185
            List<Synonym> synList = new ArrayList<>(parentNode.getTaxon().getSynonyms());
186
            Collections.sort(synList, new HomotypicGroupTaxonComparator(null));
187
            //TODO: test sorting
188

    
189
            allRecords.addAll(synList);
190
        }
191

    
192
        List<TaxonNodeDto> dtos = new ArrayList<>(pageSize==null?25:pageSize);
193
        Long totalCount = Long.valueOf(allRecords.size());
194

    
195
        TaxonName parentName = null;
196

    
197
        for(CdmBase record : PagerUtils.pageList(allRecords, pageIndex, pageSize)) {
198
            if (record.isInstanceOf(TaxonNode.class)){
199
                dtos.add(new TaxonNodeDto(CdmBase.deproxy(record, TaxonNode.class)));
200
            }else if (record.isInstanceOf(Synonym.class)){
201
                Synonym synonym = CdmBase.deproxy(record, Synonym.class);
202
                parentName = parentName == null? parentNode.getTaxon().getName(): parentName;
203
                boolean isHomotypic = synonym.getName().isHomotypic(parentName);
204
                dtos.add(new TaxonNodeDto(synonym, isHomotypic));
205
            }
206
        }
207
        return new DefaultPagerImpl<TaxonNodeDto>(pageIndex, totalCount, pageSize , dtos);
208
    }
209

    
210
    @Override
211
    public TaxonNodeDto parentDto(UUID taxonNodeUuid) {
212
        TaxonNode taxonNode = dao.load(taxonNodeUuid);
213
        if(taxonNode.getParent() != null) {
214
            return new TaxonNodeDto(taxonNode.getParent());
215
        }
216
        return null;
217
    }
218

    
219
    @Override
220
    @Autowired
221
    protected void setDao(ITaxonNodeDao dao) {
222
        this.dao = dao;
223
    }
224

    
225
    @Override
226
    @Transactional(readOnly = false)
227
    public DeleteResult makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode,
228
            SynonymType synonymType, Reference citation, String citationMicroReference)  {
229

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

    
236
        if(oldTaxonNode.equals(newAcceptedTaxonNode)){
237
            throw new IllegalArgumentException("Taxon can not be made synonym of its own.");
238
        }
239

    
240
        Classification classification = oldTaxonNode.getClassification();
241
        Taxon oldTaxon = HibernateProxyHelper.deproxy(oldTaxonNode.getTaxon());
242
        Taxon newAcceptedTaxon = (Taxon)this.taxonService.find(newAcceptedTaxonNode.getTaxon().getUuid());
243
        newAcceptedTaxon = HibernateProxyHelper.deproxy(newAcceptedTaxon);
244
        // Move oldTaxon to newTaxon
245
        //TaxonName synonymName = oldTaxon.getName();
246
        TaxonName newSynonymName = CdmBase.deproxy(oldTaxon.getName());
247
        HomotypicalGroup group = CdmBase.deproxy(newSynonymName.getHomotypicalGroup());
248
        if (synonymType == null){
249
            if (newSynonymName.isHomotypic(newAcceptedTaxon.getName())){
250
                synonymType = SynonymType.HOMOTYPIC_SYNONYM_OF();
251
            }else{
252
                synonymType = SynonymType.HETEROTYPIC_SYNONYM_OF();
253
            }
254
        }
255

    
256
        //set homotypic group
257
        TaxonName newAcceptedTaxonName = HibernateProxyHelper.deproxy(newAcceptedTaxon.getName(), TaxonName.class);
258
        newAcceptedTaxon.setName(newAcceptedTaxonName);
259
        // Move Synonym Relations to new Taxon
260
        newAcceptedTaxon.addSynonymName(newSynonymName, citation, citationMicroReference, synonymType);
261
         // Move Synonyms to new Taxon
262
        // From ticket 3163 we can move taxon with accepted name having homotypic synonyms
263
        List<Synonym> synonymsInHomotypicalGroup = null;
264

    
265
        //the synonyms of the homotypical group of the old taxon
266
        if (synonymType.equals(SynonymType.HOMOTYPIC_SYNONYM_OF())){
267
        	synonymsInHomotypicalGroup = oldTaxon.getSynonymsInGroup(group);
268
        }
269

    
270
        Set<Synonym> syns = new HashSet<>(oldTaxon.getSynonyms());
271
        for(Synonym synonym : syns){
272
            SynonymType srt;
273
            if(synonym.getHomotypicGroup()!= null
274
                    && synonym.getHomotypicGroup().equals(newAcceptedTaxonName.getHomotypicalGroup())) {
275
                srt = SynonymType.HOMOTYPIC_SYNONYM_OF();
276
            } else if(synonym.getType() != null && synonym.getType().equals(SynonymType.HOMOTYPIC_SYNONYM_OF())) {
277
            	if (synonymType.equals(SynonymType.HOMOTYPIC_SYNONYM_OF())){
278
            		srt = SynonymType.HOMOTYPIC_SYNONYM_OF();
279
            	} else{
280
            		srt = SynonymType.HETEROTYPIC_SYNONYM_OF();
281
            	}
282
            } else {
283
                if (synonymsInHomotypicalGroup != null && synonymsInHomotypicalGroup.contains(synonym)){
284
                    srt = SynonymType.HOMOTYPIC_SYNONYM_OF();
285
                }else{
286
                    srt = synonym.getType();
287
                }
288

    
289
            }
290

    
291
            newAcceptedTaxon.addSynonym(synonym, srt);
292

    
293

    
294
            /*if (synonymsInHomotypicalGroup.contains(synRelation.getSynonym()) && srt.equals(SynonymType.HETEROTYPIC_SYNONYM_OF())){
295
            	homotypicalGroupAcceptedTaxon.addTypifiedName(synRelation.getSynonym().getName());
296
            }*/
297

    
298
        }
299

    
300

    
301
        // CHILD NODES
302
        if(oldTaxonNode.getChildNodes() != null && oldTaxonNode.getChildNodes().size() != 0){
303
        	List<TaxonNode> childNodes = new ArrayList<>();
304
        	for (TaxonNode childNode : oldTaxonNode.getChildNodes()){
305
        		childNodes.add(childNode);
306
        	}
307
            for(TaxonNode childNode :childNodes){
308
                newAcceptedTaxonNode.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference()); // childNode.getSynonymToBeUsed()
309
            }
310
        }
311

    
312
        //Move Taxon RelationShips to new Taxon
313
        for(TaxonRelationship taxonRelationship : oldTaxon.getTaxonRelations()){
314
            Taxon fromTaxon = HibernateProxyHelper.deproxy(taxonRelationship.getFromTaxon());
315
            Taxon toTaxon = HibernateProxyHelper.deproxy(taxonRelationship.getToTaxon());
316
            if (fromTaxon == oldTaxon){
317
                newAcceptedTaxon.addTaxonRelation(taxonRelationship.getToTaxon(), taxonRelationship.getType(),
318
                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
319

    
320
            }else if(toTaxon == oldTaxon){
321
               fromTaxon.addTaxonRelation(newAcceptedTaxon, taxonRelationship.getType(),
322
                        taxonRelationship.getCitation(), taxonRelationship.getCitationMicroReference());
323
               taxonService.saveOrUpdate(fromTaxon);
324

    
325
            }else{
326
                logger.warn("Taxon is not part of its own Taxonrelationship");
327
            }
328
            // Remove old relationships
329

    
330
            fromTaxon.removeTaxonRelation(taxonRelationship);
331
            toTaxon.removeTaxonRelation(taxonRelationship);
332
            taxonRelationship.setToTaxon(null);
333
            taxonRelationship.setFromTaxon(null);
334
        }
335

    
336

    
337
        //Move descriptions to new taxon
338
        List<TaxonDescription> descriptions = new ArrayList<TaxonDescription>( oldTaxon.getDescriptions()); //to avoid concurrent modification errors (newAcceptedTaxon.addDescription() modifies also oldtaxon.descritpions())
339
        for(TaxonDescription description : descriptions){
340
            String message = "Description copied from former accepted taxon: %s (Old title: %s)";
341
            message = String.format(message, oldTaxon.getTitleCache(), description.getTitleCache());
342
            description.setTitleCache(message, true);
343
            //oldTaxon.removeDescription(description, false);
344
            newAcceptedTaxon.addDescription(description);
345
        }
346
        oldTaxon.clearDescriptions();
347

    
348
        taxonService.saveOrUpdate(newAcceptedTaxon);
349

    
350
        taxonService.saveOrUpdate(oldTaxon);
351
        taxonService.getSession().flush();
352

    
353
        TaxonDeletionConfigurator conf = new TaxonDeletionConfigurator();
354
        conf.setDeleteSynonymsIfPossible(false);
355
        conf.setDeleteNameIfPossible(false);
356
        DeleteResult result = taxonService.isDeletable(oldTaxon.getUuid(), conf);
357

    
358

    
359
        if (result.isOk()){
360
        	 result = taxonService.deleteTaxon(oldTaxon.getUuid(), conf, classification.getUuid());
361

    
362
        }else{
363
        	result.setStatus(Status.OK);
364
        	TaxonNodeDeletionConfigurator config = new TaxonNodeDeletionConfigurator();
365
        	config.setDeleteElement(false);
366
        	conf.setTaxonNodeConfig(config);
367
        	result.includeResult(deleteTaxonNode(oldTaxonNode, conf));
368
        }
369

    
370
        result.addUpdatedObject(newAcceptedTaxon);
371

    
372

    
373
        //oldTaxonNode.delete();
374
        return result;
375
    }
376
    @Override
377
    @Transactional(readOnly = false)
378
    public UpdateResult makeTaxonNodeSynonymsOfAnotherTaxonNode( Set<UUID> oldTaxonNodeUuids,
379
            UUID newAcceptedTaxonNodeUUIDs,
380
            SynonymType synonymType,
381
            Reference citation,
382
            String citationMicroReference) {
383
    	UpdateResult result = new UpdateResult();
384
    	for (UUID nodeUuid: oldTaxonNodeUuids) {
385
    		result.includeResult(makeTaxonNodeASynonymOfAnotherTaxonNode(nodeUuid, newAcceptedTaxonNodeUUIDs, synonymType, citation, citationMicroReference));
386
    	}
387
    	return result;
388
    }
389

    
390
    @Override
391
    @Transactional(readOnly = false)
392
    public UpdateResult makeTaxonNodeASynonymOfAnotherTaxonNode(UUID oldTaxonNodeUuid,
393
            UUID newAcceptedTaxonNodeUUID,
394
            SynonymType synonymType,
395
            Reference citation,
396
            String citationMicroReference) {
397

    
398
        TaxonNode oldTaxonNode = dao.load(oldTaxonNodeUuid);
399
        TaxonNode oldTaxonParentNode = oldTaxonNode.getParent();
400
        TaxonNode newTaxonNode = dao.load(newAcceptedTaxonNodeUUID);
401

    
402
        UpdateResult result = makeTaxonNodeASynonymOfAnotherTaxonNode(oldTaxonNode,
403
                newTaxonNode,
404
                synonymType,
405
                citation,
406
                citationMicroReference);
407
        result.addUpdatedCdmId(new CdmEntityIdentifier(oldTaxonParentNode.getId(), TaxonNode.class));
408
        result.addUpdatedCdmId(new CdmEntityIdentifier(newTaxonNode.getId(), TaxonNode.class));
409
        result.setCdmEntity(oldTaxonParentNode);
410
        return result;
411
    }
412

    
413
    @Override
414
    @Transactional(readOnly = false)
415
    public DeleteResult deleteTaxonNodes(List<TaxonNode> list, TaxonDeletionConfigurator config) {
416

    
417
        if (config == null){
418
        	config = new TaxonDeletionConfigurator();
419
        }
420
        DeleteResult result = new DeleteResult();
421
        Classification classification = null;
422
        List<TaxonNode> taxonNodes = new ArrayList<>(list);
423

    
424
        for (TaxonNode treeNode:taxonNodes){
425
        	if (treeNode != null){
426

    
427
        		TaxonNode taxonNode;
428
	            taxonNode = HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);
429
	            TaxonNode parent = taxonNode.getParent();
430
	            	//check whether the node has children or the children are already deleted
431
	            if(taxonNode.hasChildNodes()) {
432
            		List<TaxonNode> children = new ArrayList<TaxonNode> ();
433
            		List<TaxonNode> childNodesList = taxonNode.getChildNodes();
434
        			children.addAll(childNodesList);
435
        			//To avoid NPE when child is also in list of taxonNodes, remove it from the list
436
        			Iterator<TaxonNode> it = taxonNodes.iterator();
437
        			for (TaxonNode child: children) {
438
        				while (it.hasNext()) {
439
        					if (it.next().equals(child)) {
440
        						it.remove();
441
        					}
442
        				}
443
        			}
444
        			int compare = config.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling.DELETE);
445
        			boolean childHandling = (compare == 0)? true: false;
446
            		if (childHandling){
447
            			boolean changeDeleteTaxon = false;
448
            			if (!config.getTaxonNodeConfig().isDeleteTaxon()){
449
            				config.getTaxonNodeConfig().setDeleteTaxon(true);
450
            				changeDeleteTaxon = true;
451
            			}
452
            			DeleteResult resultNodes = deleteTaxonNodes(children, config);
453
            			if (!resultNodes.isOk()){
454
                            result.addExceptions(resultNodes.getExceptions());
455
                            result.setStatus(resultNodes.getStatus());
456
                        }
457
            			if (changeDeleteTaxon){
458
            				config.getTaxonNodeConfig().setDeleteTaxon(false);
459
            			}
460

    
461
            		} else {
462
            			//move the children to the parent
463

    
464
            			for (TaxonNode child: childNodesList){
465
            				parent.addChildNode(child, child.getReference(), child.getMicroReference());
466
            			}
467

    
468
            		}
469
            	}
470

    
471
	            classification = taxonNode.getClassification();
472

    
473
	            if (classification.getRootNode().equals(taxonNode)){
474
	            	classification.removeRootNode();
475
	            	classification = null;
476
	            }else if (classification.getChildNodes().contains(taxonNode)){
477
            		Taxon taxon = taxonNode.getTaxon();
478
            		classification.deleteChildNode(taxonNode);
479

    
480
	            	//node is rootNode
481
	            	if (taxon != null){
482

    
483
	            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
484
	            		    taxonService.saveOrUpdate(taxon);
485
	            		    saveOrUpdate(taxonNode);
486

    
487
			            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
488
			            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, classification.getUuid());
489
			            	if (!resultTaxon.isOk()){
490
                                result.addExceptions(resultTaxon.getExceptions());
491
                                result.setStatus(resultTaxon.getStatus());
492
                            }
493

    
494
		            	}
495
	            	}
496
            		classification = null;
497

    
498
	            } else {
499
	            	classification = null;
500
	            	Taxon taxon = taxonNode.getTaxon();
501
	            	taxon = HibernateProxyHelper.deproxy(taxon, Taxon.class);
502
	            	if (taxon != null){
503
	            		taxon.removeTaxonNode(taxonNode);
504
	            		if (config.getTaxonNodeConfig().isDeleteTaxon()){
505
			            	TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
506
			            	saveOrUpdate(taxonNode);
507
			            	taxonService.saveOrUpdate(taxon);
508
			            	DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, null);
509

    
510
                            if (!resultTaxon.isOk()){
511
                                result.addExceptions(resultTaxon.getExceptions());
512
                                result.setStatus(resultTaxon.getStatus());
513
                            }
514
		            	}
515
	            	}
516

    
517
	            }
518

    
519
	            result.addUpdatedObject(parent);
520
	            if(result.getCdmEntity() == null){
521
	                result.setCdmEntity(taxonNode);
522
                }
523
	            UUID uuid = dao.delete(taxonNode);
524
	            logger.debug("Deleted node " +uuid.toString());
525

    
526
	        }
527
        }
528
        /*if (classification != null){
529
            result.addUpdatedObject(classification);
530
        	DeleteResult resultClassification = classService.delete(classification);
531
        	 if (!resultClassification.isOk()){
532
                 result.addExceptions(resultClassification.getExceptions());
533
                 result.setStatus(resultClassification.getStatus());
534
             }
535
        }*/
536
        return result;
537
    }
538

    
539

    
540
    @Override
541
    @Transactional(readOnly = false)
542
    public DeleteResult deleteTaxonNodes(Collection<UUID> nodeUuids, TaxonDeletionConfigurator config) {
543
        List<TaxonNode> nodes = new ArrayList<>();
544
        for(UUID nodeUuid : nodeUuids) {
545
            nodes.add(dao.load(nodeUuid));
546
        }
547
        return deleteTaxonNodes(nodes, config);
548
    }
549

    
550

    
551
    @Override
552
    @Transactional(readOnly = false)
553
    public DeleteResult deleteTaxonNode(UUID nodeUUID, TaxonDeletionConfigurator config) {
554

    
555
    	TaxonNode node = HibernateProxyHelper.deproxy(dao.load(nodeUUID), TaxonNode.class);
556
    	return deleteTaxonNode(node, config);
557
    }
558

    
559
    @Override
560
    @Transactional(readOnly = false)
561
    public DeleteResult deleteTaxonNode(TaxonNode node, TaxonDeletionConfigurator config) {
562
        DeleteResult result = new DeleteResult();
563
        if (node == null){
564
            result.setAbort();
565
            result.addException(new Exception("The TaxonNode was already deleted."));
566
            return result;
567
        }
568
        Taxon taxon = null;
569
        try{
570
            taxon = HibernateProxyHelper.deproxy(node.getTaxon());
571
        }catch(NullPointerException e){
572
            result.setAbort();
573
            result.addException(new Exception("The Taxon was already deleted."));
574

    
575
        }
576
    	TaxonNode parent = HibernateProxyHelper.deproxy(node.getParent(), TaxonNode.class);
577
    	if (config == null){
578
    		config = new TaxonDeletionConfigurator();
579
    	}
580

    
581

    
582
    	if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.MOVE_TO_PARENT)){
583
    	   Object[] children = node.getChildNodes().toArray();
584
    	   TaxonNode childNode;
585
    	   for (Object child: children){
586
    	       childNode = (TaxonNode) child;
587
    	       parent.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference());
588
    	   }
589
    	}else{
590
    	    result.includeResult(deleteTaxonNodes(node.getChildNodes(), config));
591
    	}
592

    
593
    	if (taxon != null){
594
        	if (config.getTaxonNodeConfig().isDeleteTaxon() && (config.isDeleteInAllClassifications() || taxon.getTaxonNodes().size() == 1)){
595
        		result = taxonService.deleteTaxon(taxon.getUuid(), config, node.getClassification().getUuid());
596
        		result.addUpdatedObject(parent);
597
        		if (result.isOk()){
598
        			return result;
599
        		}
600
        	} else {
601
        	    result.addUpdatedObject(taxon);
602
        	}
603
    	}
604
    	result.setCdmEntity(node);
605
    	boolean success = taxon.removeTaxonNode(node);
606
    	dao.saveOrUpdate(parent);
607
    	taxonService.saveOrUpdate(taxon);
608
    	result.addUpdatedObject(parent);
609

    
610
    	if (success){
611
			result.setStatus(Status.OK);
612
			parent = HibernateProxyHelper.deproxy(parent, TaxonNode.class);
613
			int index = parent.getChildNodes().indexOf(node);
614
			if (index > -1){
615
			    parent.removeChild(index);
616
			}
617
    		if (!dao.delete(node, config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)).equals(null)){
618
    			result.addDeletedObject(node);
619
    			return result;
620
    		} else {
621
    			result.setError();
622
    			return result;
623
    		}
624
    	}else{
625
    	    if (dao.findByUuid(node.getUuid()) != null){
626
        		result.setError();
627
        		result.addException(new Exception("The node can not be removed from the taxon."));
628
    		}
629
    		return result;
630
    	}
631
    }
632

    
633

    
634
    @Override
635
    public List<TaxonNode> listAllNodesForClassification(Classification classification, Integer start, Integer end) {
636
        return dao.getTaxonOfAcceptedTaxaByClassification(classification, start, end);
637
    }
638

    
639
    @Override
640
    public int countAllNodesForClassification(Classification classification) {
641
        return dao.countTaxonOfAcceptedTaxaByClassification(classification);
642
    }
643

    
644
    @Override
645
    @Transactional
646
    public UpdateResult moveTaxonNode(UUID taxonNodeUuid, UUID targetNodeUuid, int movingType){
647
        TaxonNode taxonNode = HibernateProxyHelper.deproxy(dao.load(taxonNodeUuid), TaxonNode.class);
648
    	TaxonNode targetNode = HibernateProxyHelper.deproxy(dao.load(targetNodeUuid), TaxonNode.class);
649
    	return moveTaxonNode(taxonNode, targetNode, movingType);
650
    }
651

    
652
    @Override
653
    @Transactional
654
    public UpdateResult moveTaxonNode(TaxonNode taxonNode, TaxonNode newParent, int movingType){
655
        UpdateResult result = new UpdateResult();
656

    
657
        TaxonNode parentParent = HibernateProxyHelper.deproxy(newParent.getParent());
658
        TaxonNode oldParent = HibernateProxyHelper.deproxy(taxonNode.getParent());
659
        Integer sortIndex = -1;
660
        if (movingType == 0){
661
            sortIndex = 0;
662
        }else if (movingType == 1){
663
            sortIndex = newParent.getSortIndex();
664
            newParent = parentParent;
665
        } else if (movingType == 2){
666
            sortIndex = newParent.getSortIndex() +1;
667
            newParent = parentParent;
668
        } else{
669
            result.setAbort();
670
            result.addException(new Exception("The moving type "+ movingType +" is not supported."));
671
        }
672

    
673

    
674
        taxonNode = newParent.addChildNode(taxonNode, sortIndex, taxonNode.getReference(),  taxonNode.getMicroReference());
675
        result.addUpdatedObject(newParent);
676
        result.addUpdatedObject(oldParent);
677
        result.setCdmEntity(taxonNode);
678

    
679
        dao.saveOrUpdate(taxonNode);
680
        dao.saveOrUpdate(oldParent);
681

    
682
        return result;
683
    }
684

    
685

    
686

    
687
    @Override
688
    @Transactional
689
    public UpdateResult moveTaxonNodes(Set<UUID> taxonNodeUuids, UUID newParentNodeUuid, int movingType){
690
        UpdateResult result = new UpdateResult();
691
        TaxonNode targetNode = dao.load(newParentNodeUuid);
692
        for (UUID taxonNodeUuid: taxonNodeUuids){
693
            TaxonNode taxonNode = dao.load(taxonNodeUuid);
694
            result.includeResult(moveTaxonNode(taxonNode,targetNode, movingType));
695
        }
696
        return result;
697
    }
698

    
699
    @Override
700
    public Pager<TaxonNodeAgentRelation> pageTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,
701
            UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
702

    
703

    
704
        List<TaxonNodeAgentRelation> records = null;
705

    
706
        long count = dao.countTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid);
707
        if(PagerUtils.hasResultsInRange(count, pageIndex, pageSize)) {
708
            records = dao.listTaxonNodeAgentRelations(taxonUuid, classificationUuid,
709
                    agentUuid, rankUuid, relTypeUuid, PagerUtils.startFor(pageSize, pageIndex), PagerUtils.limitFor(pageSize), propertyPaths);
710
        }
711

    
712
        Pager<TaxonNodeAgentRelation> pager = new DefaultPagerImpl<>(pageIndex, count, pageSize, records);
713
        return pager;
714
    }
715

    
716
    @Override
717
    @Transactional
718
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, Taxon newTaxon, Reference ref, String microref){
719
        UpdateResult result = new UpdateResult();
720
        if (newTaxon.getName().getId() != 0){
721
            TaxonName name = nameService.load(newTaxon.getName().getUuid());
722
            newTaxon.setName(name);
723
        }
724
        UUID taxonUUID = taxonService.saveOrUpdate(newTaxon);
725
        newTaxon = (Taxon) taxonService.load(taxonUUID);
726

    
727
        TaxonNode parent = dao.load(parentNodeUuid);
728
        TaxonNode child = null;
729
        try{
730
            child = parent.addChildTaxon(newTaxon, parent.getReference(), parent.getMicroReference());
731
        }catch(Exception e){
732
            result.addException(e);
733
            result.setError();
734
            return result;
735
        }
736
//        child = dao.save(child);
737

    
738
        dao.saveOrUpdate(parent);
739
        result.addUpdatedObject(parent);
740
        if (child != null){
741
            result.setCdmEntity(child);
742
        }
743
        return result;
744

    
745
    }
746
    @Override
747
    @Transactional
748
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, UUID taxonUuid, Reference ref, String microref){
749
        UpdateResult result = new UpdateResult();
750
        TaxonNode parent = dao.load(parentNodeUuid);
751
        Taxon taxon = (Taxon) taxonService.load(taxonUuid);
752
        TaxonNode child = null;
753
        try{
754
            child = parent.addChildTaxon(taxon, parent.getReference(), parent.getMicroReference());
755
        }catch(Exception e){
756
            result.addException(e);
757
            result.setError();
758
            return result;
759
        }
760
//        child = dao.save(child);
761

    
762
//        dao.saveOrUpdate(child);
763
        result.addUpdatedObject(parent);
764
        if (child != null){
765
            result.setCdmEntity(child);
766
        }
767
        return result;
768

    
769
    }
770

    
771
    @Override
772
    @Transactional
773
    public UpdateResult addTaxonNodeAgentRelation(UUID taxonNodeUUID, UUID agentUUID, DefinedTerm relationshipType){
774
        UpdateResult result = new UpdateResult();
775
        TaxonNode node = dao.load(taxonNodeUUID);
776
        TeamOrPersonBase<?> agent = (TeamOrPersonBase<?>) agentService.load(agentUUID);
777
        node.addAgentRelation(relationshipType, agent);
778
        try{
779
            dao.merge(node, true);
780
        }catch (Exception e){
781
            result.setError();
782
            result.addException(e);
783
        }
784
        result.setCdmEntity(node);
785
        return result;
786
    }
787

    
788
    @Override
789
    @Transactional
790
    public UpdateResult setSecundumForSubtree(SecundumForSubtreeConfigurator config) {
791
        UpdateResult result = new UpdateResult();
792
       // IProgressMonitor monitor = config.getMonitor();
793
        IProgressMonitor monitor = config.getMonitor();
794
        if (monitor == null){
795
            monitor = DefaultProgressMonitor.NewInstance();
796
        }
797
        TaxonNode subTree = load(config.getSubtreeUuid());
798
        TreeIndex subTreeIndex = null;
799
        Reference newSec = null;
800
        if (config.getNewSecundum() != null){
801
            newSec = refService.load(config.getNewSecundum().getUuid());
802
        }
803
        if (subTree != null){
804
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
805
            Long count = dao.countChildrenOf(subTree, subTree.getClassification(), true);
806
            int intCount = count.intValue();
807
            monitor.beginTask("Update Secundum Reference", intCount);
808
        }
809

    
810

    
811
        if (config.getSubtreeUuid() == null){
812
            result.setError();
813
            result.addException(new NullPointerException("No subtree given"));
814
            monitor.done();
815
            return result;
816
        }
817

    
818
        if (subTree == null){
819
            result.setError();
820
            result.addException(new NullPointerException("Subtree does not exist"));
821
            monitor.done();
822
            return result;
823
        }
824

    
825

    
826
        //Reference ref = config.getNewSecundum();
827
        if (config.isIncludeAcceptedTaxa()){
828
            monitor.subTask("Update Accepted Taxa");
829

    
830
            Set<TaxonBase> updatedTaxa = dao.setSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail());
831
            result.addUpdatedObjects(updatedTaxa);
832
        }
833
        if (config.isIncludeSynonyms()){
834
           monitor.subTask("Update Synonyms");
835
           Set<TaxonBase> updatedSynonyms = dao.setSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail());
836
           result.addUpdatedObjects(updatedSynonyms);
837
        }
838

    
839
        monitor.done();
840
        return result;
841
    }
842

    
843

    
844
    /**
845
     * {@inheritDoc}
846
     */
847
    @Override
848
    @Transactional
849
    public UpdateResult setPublishForSubtree(UUID subtreeUuid, boolean publish, boolean includeAcceptedTaxa,
850
            boolean includeSynonyms, boolean includeSharedTaxa, IProgressMonitor monitor) {
851
        UpdateResult result = new UpdateResult();
852
       // IProgressMonitor monitor = config.getMonitor();
853
        if (monitor == null){
854
            monitor = DefaultProgressMonitor.NewInstance();
855
        }
856
        monitor.beginTask("Update publish flag", 100);
857
        if (subtreeUuid == null){
858
            result.setError();
859
            result.addException(new NullPointerException("No subtree given"));
860
            monitor.done();
861
            return result;
862
        }
863
        TaxonNode subTree = find(subtreeUuid);
864
        if (subTree == null){
865
            result.setError();
866
            result.addException(new NullPointerException("Subtree does not exist"));
867
            monitor.done();
868
            return result;
869
        }
870
        TreeIndex subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
871

    
872

    
873
        if (includeAcceptedTaxa){
874
            monitor.subTask("Update Accepted Taxa");
875
            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa);
876
//            taxonService.saveOrUpdate(updatedTaxa);
877
            result.addUpdatedObjects(updatedTaxa);
878
        }
879
        if (includeSynonyms){
880
            monitor.subTask("Update Synonyms");
881
            Set<TaxonBase> updatedSynonyms = dao.setPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa);
882
//            taxonService.saveOrUpdate(updatedSynonyms);
883
            result.addUpdatedObjects(updatedSynonyms);
884
        }
885
        monitor.done();
886
        return result;
887
    }
888

    
889

    
890
    @Override
891
    public long count(TaxonNodeFilter filter){
892
        return nodeFilterDao.count(filter);
893
    }
894

    
895
    @Override
896
    public List<UUID> uuidList(TaxonNodeFilter filter){
897
        return nodeFilterDao.listUuids(filter);
898
    }
899

    
900
    @Override
901
    public List<Integer> idList(TaxonNodeFilter filter){
902
        return nodeFilterDao.idList(filter);
903
    }
904

    
905
    @Override
906
    @Transactional
907
    public UUID monitSetSecundum(final SecundumForSubtreeConfigurator configurator) {
908
        RemotingProgressMonitorThread monitorThread = new RemotingProgressMonitorThread() {
909
            @Override
910
            public Serializable doRun(IRemotingProgressMonitor monitor) {
911
                configurator.setMonitor(monitor);
912
                UpdateResult result = setSecundumForSubtree(configurator);
913
                return result;
914
            }
915
        };
916
        UUID uuid = progressMonitorService.registerNewRemotingMonitor(monitorThread);
917
        monitorThread.setPriority(3);
918
        monitorThread.start();
919
        return uuid;
920
    }
921

    
922
}
(93-93/101)