Project

General

Profile

Download (35.5 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 ITaxonNodeFilterDao nodeFilterDao;
91

    
92
    @Autowired
93
    IProgressMonitorService progressMonitorService;
94

    
95

    
96
    @Override
97
    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
98
            List<String> propertyPaths, boolean recursive, NodeSortMode sortMode) {
99

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

    
108
        HHH_9751_Util.removeAllNull(childNodes);
109

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

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

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

    
137
    /**
138
     * {@inheritDoc}
139
     */
140
    @Override
141
    public List<UuidAndTitleCache<TaxonNode>> listChildNodesAsUuidAndTitleCache(UuidAndTitleCache<TaxonNode> parent) {
142
        return dao.listChildNodesAsUuidAndTitleCache(parent);
143
    }
144

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

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

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

    
172
        TaxonNode parentNode = dao.load(taxonNodeUuid);
173

    
174
        List<CdmBase> allRecords = new ArrayList<>();
175

    
176
        //acceptedTaxa
177
        List<TaxonNode> childNodes = loadChildNodesOfTaxonNode(parentNode, null, recursive, sortMode);
178
        allRecords.addAll(childNodes);
179

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

    
186
            allRecords.addAll(synList);
187
        }
188

    
189
        List<TaxonNodeDto> dtos = new ArrayList<>(pageSize==null?25:pageSize);
190
        Long totalCount = Long.valueOf(allRecords.size());
191

    
192
        TaxonName parentName = null;
193

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

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

    
216
    @Override
217
    @Autowired
218
    protected void setDao(ITaxonNodeDao dao) {
219
        this.dao = dao;
220
    }
221

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

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

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

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

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

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

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

    
287
            }
288

    
289
            newAcceptedTaxon.addSynonym(synonym, srt);
290

    
291

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

    
296
        }
297

    
298

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

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

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

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

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

    
335

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

    
347
        taxonService.saveOrUpdate(newAcceptedTaxon);
348

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

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

    
357

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

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

    
369
        result.addUpdatedObject(newAcceptedTaxon);
370

    
371

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

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

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

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

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

    
416
        if (config == null){
417
        	config = new TaxonDeletionConfigurator();
418
        }
419
        DeleteResult result = new DeleteResult();
420
        List<UUID> deletedUUIDs = new ArrayList<UUID>();
421
        Classification classification = null;
422
        List<TaxonNode> taxonNodes = new ArrayList<TaxonNode>(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<TaxonNode>();
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
    	    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
    			return result;
619
    		} else {
620
    			result.setError();
621
    			return result;
622
    		}
623
    	}else{
624
    	    if (dao.findByUuid(node.getUuid()) != null){
625
        		result.setError();
626
        		result.addException(new Exception("The node can not be removed from the taxon."));
627
    		}
628
    		return result;
629
    	}
630
    }
631

    
632

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

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

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

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

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

    
672

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

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

    
681
        return result;
682
    }
683

    
684

    
685

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

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

    
702

    
703
        List<TaxonNodeAgentRelation> records = null;
704

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

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

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

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

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

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

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

    
768
    }
769

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

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

    
805

    
806
        if (config.getSubtreeUuid() == null){
807
            result.setError();
808
            result.addException(new NullPointerException("No subtree given"));
809
            monitor.done();
810
            return result;
811
        }
812

    
813
        if (subTree == null){
814
            result.setError();
815
            result.addException(new NullPointerException("Subtree does not exist"));
816
            monitor.done();
817
            return result;
818
        }
819

    
820

    
821
        //Reference ref = config.getNewSecundum();
822
        if (config.isIncludeAcceptedTaxa()){
823
            monitor.subTask("Update Accepted Taxa");
824
            Set<TaxonBase> updatedTaxa = dao.setSecundumForSubtreeAcceptedTaxa(subTreeIndex, config.getNewSecundum(), config.isOverwriteExistingAccepted(), config.isIncludeSharedTaxa(), config.isEmptySecundumDetail());
825
            result.addUpdatedObjects(updatedTaxa);
826
        }
827
        if (config.isIncludeSynonyms()){
828
           monitor.subTask("Update Synonyms");
829
           Set<TaxonBase> updatedSynonyms = dao.setSecundumForSubtreeSynonyms(subTreeIndex, config.getNewSecundum(), config.isOverwriteExistingSynonyms(), config.isIncludeSharedTaxa() , config.isEmptySecundumDetail());
830
           result.addUpdatedObjects(updatedSynonyms);
831
        }
832

    
833
        monitor.done();
834
        return result;
835
    }
836

    
837

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

    
866

    
867
        if (includeAcceptedTaxa){
868
            monitor.subTask("Update Accepted Taxa");
869
            Set<TaxonBase> updatedTaxa = dao.setPublishForSubtreeAcceptedTaxa(subTreeIndex, publish, includeSharedTaxa);
870
//            taxonService.saveOrUpdate(updatedTaxa);
871
            result.addUpdatedObjects(updatedTaxa);
872
        }
873
        if (includeSynonyms){
874
            monitor.subTask("Update Synonyms");
875
            Set<TaxonBase> updatedSynonyms = dao.setPublishForSubtreeSynonyms(subTreeIndex, publish, includeSharedTaxa);
876
//            taxonService.saveOrUpdate(updatedSynonyms);
877
            result.addUpdatedObjects(updatedSynonyms);
878
        }
879
        monitor.done();
880
        return result;
881
    }
882

    
883

    
884
    @Override
885
    public long count(TaxonNodeFilter filter){
886
        return nodeFilterDao.count(filter);
887
    }
888

    
889
    @Override
890
    public List<UUID> uuidList(TaxonNodeFilter filter){
891
        return nodeFilterDao.listUuids(filter);
892
    }
893

    
894
    @Override
895
    public List<Integer> idList(TaxonNodeFilter filter){
896
        return nodeFilterDao.idList(filter);
897
    }
898

    
899
    @Override
900
    public UUID monitSetSecundum(final SecundumForSubtreeConfigurator configurator) {
901
        RemotingProgressMonitorThread monitorThread = new RemotingProgressMonitorThread() {
902
            @Override
903
            public Serializable doRun(IRemotingProgressMonitor monitor) {
904
                configurator.setMonitor(monitor);
905
                UpdateResult result = setSecundumForSubtree(configurator);
906
                return result;
907
            }
908
        };
909
        UUID uuid = progressMonitorService.registerNewRemotingMonitor(monitorThread);
910
        monitorThread.setPriority(3);
911
        monitorThread.start();
912
        return uuid;
913
    }
914

    
915
	
916

    
917

    
918

    
919

    
920
}
(93-93/101)