Project

General

Profile

Download (36.1 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
 * @since 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.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> listChildNodesAsTaxonNodeDto(UuidAndTitleCache<TaxonNode> parent) {
145
        return dao.listChildNodesAsTaxonNodeDto(parent);
146
    }
147

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

    
156

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

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

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

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

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

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

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

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

    
206
            allRecords.addAll(synList);
207
        }
208

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

    
212
        TaxonName parentName = null;
213

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

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

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

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

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

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

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

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

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

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

    
306
            }
307

    
308
            newAcceptedTaxon.addSynonym(synonym, srt);
309

    
310

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

    
315
        }
316

    
317

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

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

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

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

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

    
353

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

    
365
        taxonService.saveOrUpdate(newAcceptedTaxon);
366

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

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

    
375

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

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

    
387
        result.addUpdatedObject(newAcceptedTaxon);
388

    
389

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

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

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

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

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

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

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

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

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

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

    
485
            		}
486
            	}
487

    
488
	            classification = taxonNode.getClassification();
489

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

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

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

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

    
511
		            	}
512
	            	}
513
            		classification = null;
514

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

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

    
534
	            }
535

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

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

    
556

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

    
567

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

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

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

    
592
        }
593

    
594

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

    
600

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

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

    
631
    	result.addUpdatedObject(parent);
632

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

    
659

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

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

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

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

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

    
699

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

    
705
        dao.saveOrUpdate(taxonNode);
706
        dao.saveOrUpdate(oldParent);
707

    
708
        return result;
709
    }
710

    
711

    
712

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

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

    
729

    
730
        List<TaxonNodeAgentRelation> records = null;
731

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

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

    
742
    @Override
743
    @Transactional
744
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, Taxon newTaxon, Reference ref, String microref){
745
        UpdateResult result = new UpdateResult();
746
        if (newTaxon.getName().getId() != 0){
747
            TaxonName name = nameService.load(newTaxon.getName().getUuid());
748
            newTaxon.setName(name);
749
        }
750
        UUID taxonUUID = taxonService.saveOrUpdate(newTaxon);
751
        newTaxon = (Taxon) taxonService.load(taxonUUID);
752

    
753
        TaxonNode parent = dao.load(parentNodeUuid);
754
        TaxonNode child = null;
755
        try{
756
            child = parent.addChildTaxon(newTaxon, parent.getReference(), parent.getMicroReference());
757
        }catch(Exception e){
758
            result.addException(e);
759
            result.setError();
760
            return result;
761
        }
762
//        child = dao.save(child);
763

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

    
771
    }
772
    @Override
773
    @Transactional
774
    public UpdateResult createNewTaxonNode(UUID parentNodeUuid, UUID taxonUuid, Reference ref, String microref){
775
        UpdateResult result = new UpdateResult();
776
        TaxonNode parent = dao.load(parentNodeUuid);
777
        Taxon taxon = (Taxon) taxonService.load(taxonUuid);
778
        TaxonNode child = null;
779
        try{
780
            child = parent.addChildTaxon(taxon, parent.getReference(), parent.getMicroReference());
781
        }catch(Exception e){
782
            result.addException(e);
783
            result.setError();
784
            return result;
785
        }
786
//        child = dao.save(child);
787

    
788
//        dao.saveOrUpdate(child);
789
        result.addUpdatedObject(parent);
790
        if (child != null){
791
            result.setCdmEntity(child);
792
        }
793
        return result;
794

    
795
    }
796

    
797
    @Override
798
    @Transactional
799
    public UpdateResult addTaxonNodeAgentRelation(UUID taxonNodeUUID, UUID agentUUID, DefinedTerm relationshipType){
800
        UpdateResult result = new UpdateResult();
801
        TaxonNode node = dao.load(taxonNodeUUID);
802
        TeamOrPersonBase<?> agent = (TeamOrPersonBase<?>) agentService.load(agentUUID);
803
        node.addAgentRelation(relationshipType, agent);
804
        try{
805
            dao.merge(node, true);
806
        }catch (Exception e){
807
            result.setError();
808
            result.addException(e);
809
        }
810
        result.setCdmEntity(node);
811
        return result;
812
    }
813

    
814
    @Override
815
    @Transactional
816
    public UpdateResult setSecundumForSubtree(SecundumForSubtreeConfigurator config) {
817
        UpdateResult result = new UpdateResult();
818
        IProgressMonitor monitor = config.getMonitor();
819
        if (monitor == null){
820
            monitor = DefaultProgressMonitor.NewInstance();
821
        }
822
        TaxonNode subTree = load(config.getSubtreeUuid());
823
        TreeIndex subTreeIndex = null;
824
        Reference newSec = null;
825
        if (config.getNewSecundum() != null){
826
            newSec = refService.load(config.getNewSecundum().getUuid());
827
        }
828
        if (subTree != null){
829
            subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
830
            Long count = dao.countChildrenOf(subTree, subTree.getClassification(), true);
831
            int intCount = count.intValue();
832
            monitor.beginTask("Update Secundum Reference", intCount);
833
        }
834

    
835

    
836
        if (config.getSubtreeUuid() == null){
837
            result.setError();
838
            result.addException(new NullPointerException("No subtree given"));
839
            monitor.done();
840
            return result;
841
        }
842

    
843
        if (subTree == null){
844
            result.setError();
845
            result.addException(new NullPointerException("Subtree does not exist"));
846
            monitor.done();
847
            return result;
848
        }
849

    
850

    
851
        //Reference ref = config.getNewSecundum();
852
        if (config.isIncludeAcceptedTaxa()){
853
            monitor.subTask("Update Accepted Taxa");
854

    
855
            Set<TaxonBase> updatedTaxa = dao.setSecundumForSubtreeAcceptedTaxa(subTreeIndex, newSec, config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail());
856
            result.addUpdatedObjects(updatedTaxa);
857
        }
858
        if (config.isIncludeSynonyms()){
859
           monitor.subTask("Update Synonyms");
860
           Set<TaxonBase> updatedSynonyms = dao.setSecundumForSubtreeSynonyms(subTreeIndex, newSec, config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail());
861
           result.addUpdatedObjects(updatedSynonyms);
862
        }
863

    
864
        monitor.done();
865
        return result;
866
    }
867

    
868

    
869
    /**
870
     * {@inheritDoc}
871
     */
872
    @Override
873
    @Transactional
874
    public UpdateResult setPublishForSubtree(UUID subtreeUuid, boolean publish, boolean includeAcceptedTaxa,
875
            boolean includeSynonyms, boolean includeSharedTaxa, IProgressMonitor monitor) {
876
        UpdateResult result = new UpdateResult();
877
       // IProgressMonitor monitor = config.getMonitor();
878
        if (monitor == null){
879
            monitor = DefaultProgressMonitor.NewInstance();
880
        }
881
        monitor.beginTask("Update publish flag", 100);
882
        if (subtreeUuid == null){
883
            result.setError();
884
            result.addException(new NullPointerException("No subtree given"));
885
            monitor.done();
886
            return result;
887
        }
888
        TaxonNode subTree = find(subtreeUuid);
889
        if (subTree == null){
890
            result.setError();
891
            result.addException(new NullPointerException("Subtree does not exist"));
892
            monitor.done();
893
            return result;
894
        }
895
        TreeIndex subTreeIndex = TreeIndex.NewInstance(subTree.treeIndex());
896

    
897

    
898
        if (includeAcceptedTaxa){
899
            monitor.subTask("Update Accepted Taxa");
900
            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa);
901
//            taxonService.saveOrUpdate(updatedTaxa);
902
            result.addUpdatedObjects(updatedTaxa);
903
        }
904
        if (includeSynonyms){
905
            monitor.subTask("Update Synonyms");
906
            Set<TaxonBase> updatedSynonyms = dao.setPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa);
907
//            taxonService.saveOrUpdate(updatedSynonyms);
908
            result.addUpdatedObjects(updatedSynonyms);
909
        }
910
        monitor.done();
911
        return result;
912
    }
913

    
914

    
915
    @Override
916
    public long count(TaxonNodeFilter filter){
917
        return nodeFilterDao.count(filter);
918
    }
919

    
920
    @Override
921
    public List<UUID> uuidList(TaxonNodeFilter filter){
922
        return nodeFilterDao.listUuids(filter);
923
    }
924

    
925
    @Override
926
    public List<Integer> idList(TaxonNodeFilter filter){
927
        return nodeFilterDao.idList(filter);
928
    }
929

    
930
    @Override
931
    @Transactional
932
    public UUID monitSetSecundum(final SecundumForSubtreeConfigurator configurator) {
933
        RemotingProgressMonitorThread monitorThread = new RemotingProgressMonitorThread() {
934
            @Override
935
            public Serializable doRun(IRemotingProgressMonitor monitor) {
936
                configurator.setMonitor(monitor);
937
                UpdateResult result = setSecundumForSubtree(configurator);
938
                return result;
939
            }
940
        };
941
        UUID uuid = progressMonitorService.registerNewRemotingMonitor(monitorThread);
942
        monitorThread.setPriority(3);
943
        monitorThread.start();
944
        return uuid;
945
    }
946

    
947
}
(97-97/105)