Project

General

Profile

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

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

    
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.Comparator;
17
import java.util.HashMap;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.TreeMap;
21
import java.util.UUID;
22

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

    
29
import eu.etaxonomy.cdm.api.service.config.CreateHierarchyForClassificationConfigurator;
30
import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;
31
import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
32
import eu.etaxonomy.cdm.api.service.pager.Pager;
33
import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
34
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
35
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
36
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
37
import eu.etaxonomy.cdm.model.common.CdmBase;
38
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
39
import eu.etaxonomy.cdm.model.description.TaxonDescription;
40
import eu.etaxonomy.cdm.model.media.Media;
41
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
42
import eu.etaxonomy.cdm.model.media.MediaUtils;
43
import eu.etaxonomy.cdm.model.name.NonViralName;
44
import eu.etaxonomy.cdm.model.name.Rank;
45
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
46
import eu.etaxonomy.cdm.model.taxon.Classification;
47
import eu.etaxonomy.cdm.model.taxon.ITaxonNodeComparator;
48
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
49
import eu.etaxonomy.cdm.model.taxon.Taxon;
50
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
51
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
52
import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;
53
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
54
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
55
import eu.etaxonomy.cdm.persistence.dto.ClassificationLookupDTO;
56
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
57
import eu.etaxonomy.cdm.persistence.query.OrderHint;
58
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
59
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
60

    
61
/**
62
 * @author n.hoffmann
63
 * @created Sep 21, 2009
64
 */
65
@Service
66
@Transactional(readOnly = true)
67
public class ClassificationServiceImpl extends IdentifiableServiceBase<Classification, IClassificationDao>
68
    implements IClassificationService {
69
    private static final Logger logger = Logger.getLogger(ClassificationServiceImpl.class);
70

    
71
    @Autowired
72
    private ITaxonNodeDao taxonNodeDao;
73

    
74
    @Autowired
75
    private ITaxonDao taxonDao;
76

    
77
    @Autowired
78
    private IBeanInitializer defaultBeanInitializer;
79

    
80
    @Override
81
    @Autowired
82
    protected void setDao(IClassificationDao dao) {
83
        this.dao = dao;
84
    }
85

    
86
    private Comparator<? super TaxonNode> taxonNodeComparator;
87

    
88
    @Autowired
89
    public void setTaxonNodeComparator(ITaxonNodeComparator<? super TaxonNode> taxonNodeComparator){
90
        this.taxonNodeComparator = (Comparator<? super TaxonNode>) taxonNodeComparator;
91
    }
92

    
93
    @Override
94
    public TaxonNode loadTaxonNodeByTaxon(Taxon taxon, UUID classificationUuid, List<String> propertyPaths){
95
        Classification tree = dao.load(classificationUuid);
96
        TaxonNode node = tree.getNode(taxon);
97

    
98
        return loadTaxonNode(node.getUuid(), propertyPaths);
99
    }
100

    
101
    @Override
102
    @Deprecated // use loadTaxonNode(UUID, List<String>) instead
103
    public TaxonNode loadTaxonNode(TaxonNode taxonNode, List<String> propertyPaths){
104
        return taxonNodeDao.load(taxonNode.getUuid(), propertyPaths);
105
    }
106

    
107
    public TaxonNode loadTaxonNode(UUID taxonNodeUuid, List<String> propertyPaths){
108
        return taxonNodeDao.load(taxonNodeUuid, propertyPaths);
109
    }
110

    
111
    @Override
112
    public List<TaxonNode> listRankSpecificRootNodes(Classification classification, Rank rank, Integer pageSize,
113
            Integer pageIndex, List<String> propertyPaths) {
114
        return pageRankSpecificRootNodes(classification, rank, pageSize, pageIndex, propertyPaths).getRecords();
115
    }
116

    
117
    @Override
118
    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, Rank rank, Integer pageSize,
119
            Integer pageIndex, List<String> propertyPaths) {
120
        long[] numberOfResults = dao.countRankSpecificRootNodes(classification, rank);
121
        long totalNumberOfResults = numberOfResults[0] + (numberOfResults.length > 1 ? numberOfResults[1] : 0);
122

    
123
        List<TaxonNode> results = new ArrayList<TaxonNode>();
124

    
125
        if (AbstractPagerImpl.hasResultsInRange(totalNumberOfResults, pageIndex, pageSize)) { // no point checking again
126
            Integer limit = PagerUtils.limitFor(pageSize);
127
            Integer start = PagerUtils.startFor(pageSize, pageIndex);
128

    
129
            Integer remainingLimit = limit;
130
            int[] queryIndexes = rank == null ? new int[]{0} : new int[]{0,1};
131

    
132
            for(int queryIndex: queryIndexes) {
133
                if(start != null && start > numberOfResults[queryIndex]) {
134
                    // start in next query with new start value
135
                    start = start - (int)numberOfResults[queryIndex];
136
                    continue;
137
                }
138

    
139
                List<TaxonNode> perQueryResults = dao.listRankSpecificRootNodes(classification, rank, remainingLimit, start, propertyPaths, queryIndex);
140
                results.addAll(perQueryResults);
141
                if(remainingLimit != null ){
142
                    remainingLimit = remainingLimit - results.size();
143
                    if(remainingLimit <= 0) {
144
                        // no need to run further queries if first query returned enough items!
145
                        break;
146
                    }
147
                    // start at with fist item of next query to fetch the remaining items
148
                    start = 0;
149
                }
150
            }
151
        }
152
//        long start_t = System.currentTimeMillis();
153
        Collections.sort(results, taxonNodeComparator); // TODO is ordering during the hibernate query in the dao possible?
154
//        System.err.println("service.pageRankSpecificRootNodes() - Collections.sort(results,  taxonNodeComparator) " + (System.currentTimeMillis() - start_t));
155
        return new DefaultPagerImpl<TaxonNode>(pageIndex, (int) totalNumberOfResults, pageSize, results);
156

    
157
    }
158

    
159
    /**
160
     * @implements {@link IClassificationService#loadTreeBranch(TaxonNode, Rank, List)
161
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#loadTreeBranchTo(eu.etaxonomy.cdm.model.taxon.TaxonNode, eu.etaxonomy.cdm.model.name.Rank, java.util.List)
162
     * FIXME Candidate for harmonization
163
     * move to classification service
164
     */
165
    @Override
166
    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, Rank baseRank, List<String> propertyPaths){
167

    
168
        TaxonNode thisNode = taxonNodeDao.load(taxonNode.getUuid(), propertyPaths);
169
        List<TaxonNode> pathToRoot = new ArrayList<TaxonNode>();
170
        pathToRoot.add(thisNode);
171

    
172
        while(!thisNode.isTopmostNode()){
173
            //TODO why do we need to deproxy here?
174
            //     without this thisNode.getParent() will return NULL in
175
            //     some cases (environment dependend?) even if the parent exits
176
            TaxonNode parentNode = CdmBase.deproxy(thisNode, TaxonNode.class).getParent();
177

    
178
            if(parentNode == null){
179
                throw new NullPointerException("taxonNode " + thisNode + " must have a parent since it is not top most");
180
            }
181
            if(parentNode.getTaxon() == null){
182
                throw new NullPointerException("The taxon associated with taxonNode " + parentNode + " is NULL");
183
            }
184
            if(parentNode.getTaxon().getName() == null){
185
                throw new NullPointerException("The name of the taxon associated with taxonNode " + parentNode + " is NULL");
186
            }
187

    
188
            Rank parentNodeRank = parentNode.getTaxon().getName() == null ? null : parentNode.getTaxon().getName().getRank();
189
            // stop if the next parent is higher than the baseRank
190
            if(baseRank != null && parentNodeRank != null && baseRank.isLower(parentNodeRank)){
191
                break;
192
            }
193

    
194
            pathToRoot.add(parentNode);
195
            thisNode = parentNode;
196
        }
197

    
198
        // initialize and invert order of nodes in list
199
        defaultBeanInitializer.initializeAll(pathToRoot, propertyPaths);
200
        Collections.reverse(pathToRoot);
201

    
202
        return pathToRoot;
203
    }
204

    
205
    @Override
206
    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification, Rank baseRank, List<String> propertyPaths){
207
        Classification tree = dao.load(classification.getUuid());
208
        taxon = (Taxon) taxonDao.load(taxon.getUuid());
209
        TaxonNode node = tree.getNode(taxon);
210
        if(node == null){
211
            logger.warn("The specified taxon is not found in the given tree.");
212
            return null;
213
        }
214
        return loadTreeBranch(node, baseRank, propertyPaths);
215
    }
216

    
217

    
218
    @Override
219
    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
220
            List<String> propertyPaths) {
221
        taxonNode = taxonNodeDao.load(taxonNode.getUuid());
222
        List<TaxonNode> childNodes = new ArrayList<TaxonNode>(taxonNode.getChildNodes());
223
        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
224
        Collections.sort(childNodes, taxonNodeComparator);
225
        return childNodes;
226
    }
227

    
228
    @Override
229
    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
230
            Integer pageIndex, List<String> propertyPaths){
231

    
232
        Classification classification = dao.load(classificationUuid);
233
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
234

    
235
        List<TaxonNode> results = dao.listChildrenOf(taxon, classification, pageSize, pageIndex, propertyPaths);
236
        Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
237
        return results;
238
    }
239

    
240
    @Override
241
    public Pager<TaxonNode> pageSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
242
            Integer pageIndex, List<String> propertyPaths){
243

    
244
        Classification classification = dao.load(classificationUuid);
245
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
246

    
247
        long numberOfResults = dao.countSiblingsOf(taxon, classification);
248

    
249
        List<TaxonNode> results;
250
        if(PagerUtils.hasResultsInRange(numberOfResults, pageIndex, pageSize)) {
251
            results = dao.listSiblingsOf(taxon, classification, pageSize, pageIndex, propertyPaths);
252
            Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
253
        } else {
254
            results = new ArrayList<>();
255
        }
256

    
257
        return new DefaultPagerImpl<TaxonNode>(pageIndex, numberOfResults, pageSize, results);
258
    }
259

    
260
    @Override
261
    public List<TaxonNode> listSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
262
            Integer pageIndex, List<String> propertyPaths){
263

    
264
        Pager<TaxonNode> pager = pageSiblingsOfTaxon(taxonUuid, classificationUuid, pageSize, pageIndex, propertyPaths);
265
        return pager.getRecords();
266
    }
267

    
268
    @Override
269
    public TaxonNode getTaxonNodeByUuid(UUID uuid) {
270
        return taxonNodeDao.findByUuid(uuid);
271
    }
272

    
273
    @Override
274
    public ITaxonTreeNode getTreeNodeByUuid(UUID uuid){
275
        ITaxonTreeNode treeNode = taxonNodeDao.findByUuid(uuid);
276
        if(treeNode == null){
277
            treeNode = dao.findByUuid(uuid);
278
        }
279

    
280
        return treeNode;
281
    }
282

    
283
    @Override
284
    public List<Classification> listClassifications(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
285
        return dao.list(limit, start, orderHints, propertyPaths);
286
    }
287

    
288
    @Override
289
    public UUID removeTaxonNode(TaxonNode taxonNode) {
290
        return taxonNodeDao.delete(taxonNode);
291
    }
292
    @Override
293
    public UUID removeTreeNode(ITaxonTreeNode treeNode) {
294
        if(treeNode instanceof Classification){
295
            return dao.delete((Classification) treeNode);
296
        }else if(treeNode instanceof TaxonNode){
297
            return taxonNodeDao.delete((TaxonNode)treeNode);
298
        }
299
        return null;
300
    }
301
    @Override
302
    public UUID saveTaxonNode(TaxonNode taxonNode) {
303
        return taxonNodeDao.save(taxonNode).getUuid();
304
    }
305

    
306
    @Override
307
    public Map<UUID, TaxonNode> saveTaxonNodeAll(
308
            Collection<TaxonNode> taxonNodeCollection) {
309
        return taxonNodeDao.saveAll(taxonNodeCollection);
310
    }
311

    
312
    @Override
313
    public UUID saveTreeNode(ITaxonTreeNode treeNode) {
314
        if(treeNode instanceof Classification){
315
            return dao.save((Classification) treeNode).getUuid();
316
        }else if(treeNode instanceof TaxonNode){
317
            return taxonNodeDao.save((TaxonNode)treeNode).getUuid();
318
        }
319
        return null;
320
    }
321

    
322
    @Override
323
    public List<TaxonNode> getAllNodes(){
324
        return taxonNodeDao.list(null,null);
325
    }
326

    
327
    @Override
328
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, List<UUID> excludeTaxa, Integer limit, String pattern) {
329
        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid), excludeTaxa, limit, pattern);
330
    }
331

    
332
    @Override
333
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, List<UUID> excludeTaxa, Integer limit, String pattern) {
334
        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, excludeTaxa, limit, pattern);
335
    }
336

    
337
    @Override
338
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, List<UUID> excludeTaxa) {
339
        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid), excludeTaxa, null, null);
340
    }
341

    
342
    @Override
343
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, List<UUID> excludeTaxa) {
344
        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, excludeTaxa, null, null);
345
    }
346

    
347
    @Override
348
    public List<UuidAndTitleCache<Classification>> getUuidAndTitleCache(Integer limit, String pattern) {
349
        return dao.getUuidAndTitleCache(limit, pattern);
350
    }
351

    
352
    @Override
353
    public Map<UUID, List<MediaRepresentation>> getAllMediaForChildNodes(
354
            TaxonNode taxonNode, List<String> propertyPaths, int size,
355
            int height, int widthOrDuration, String[] mimeTypes) {
356

    
357
        TreeMap<UUID, List<MediaRepresentation>> result = new TreeMap<UUID, List<MediaRepresentation>>();
358
        List<Media> taxonMedia = new ArrayList<Media>();
359
        List<MediaRepresentation> mediaRepresentations = new ArrayList<MediaRepresentation>();
360

    
361
        //add all media of the children to the result map
362
        if (taxonNode != null){
363

    
364
            List<TaxonNode> nodes = new ArrayList<TaxonNode>();
365

    
366
            nodes.add(loadTaxonNode(taxonNode, propertyPaths));
367
            nodes.addAll(loadChildNodesOfTaxonNode(taxonNode, propertyPaths));
368

    
369
            if (nodes != null){
370
                for(TaxonNode node : nodes){
371
                    Taxon taxon = node.getTaxon();
372
                    for (TaxonDescription taxonDescription: taxon.getDescriptions()){
373
                        for (DescriptionElementBase descriptionElement: taxonDescription.getElements()){
374
                            for(Media media : descriptionElement.getMedia()){
375
                                taxonMedia.add(media);
376

    
377
                                //find the best matching representation
378
                                mediaRepresentations.add(MediaUtils.findBestMatchingRepresentation(media,null, size, height, widthOrDuration, mimeTypes));
379

    
380
                            }
381
                        }
382
                    }
383
                    result.put(taxon.getUuid(), mediaRepresentations);
384

    
385
                }
386
            }
387

    
388
        }
389

    
390
        return result;
391

    
392
    }
393

    
394
    @Override
395
    public Map<UUID, List<MediaRepresentation>> getAllMediaForChildNodes(Taxon taxon, Classification taxTree, List<String> propertyPaths, int size, int height, int widthOrDuration, String[] mimeTypes){
396
        TaxonNode node = taxTree.getNode(taxon);
397

    
398
        return getAllMediaForChildNodes(node, propertyPaths, size, height, widthOrDuration, mimeTypes);
399
    }
400

    
401
    @Override
402
    @Transactional(readOnly = false)
403
    public void updateTitleCache(Class<? extends Classification> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<Classification> cacheStrategy, IProgressMonitor monitor) {
404
        if (clazz == null){
405
            clazz = Classification.class;
406
        }
407
        super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
408
    }
409

    
410
    /**
411
     *
412
     * @param allNodesOfClassification
413
     * @return null - if  allNodesOfClassification is empty <br>
414
     */
415

    
416
    private Map<String, List<TaxonNode>> getSortedGenusList(Collection<TaxonNode> allNodesOfClassification){
417

    
418
    	if(allNodesOfClassification == null || allNodesOfClassification.isEmpty()){
419
    		return null;
420
    	}
421
    	Map<String, List<TaxonNode>> sortedGenusMap = new HashMap<String, List<TaxonNode>>();
422
    	for(TaxonNode node:allNodesOfClassification){
423
    		final TaxonNode tn = node;
424
    		Taxon taxon = node.getTaxon();
425
    		NonViralName name = CdmBase.deproxy(taxon.getName(), NonViralName.class);
426
    		String genusOrUninomial = name.getGenusOrUninomial();
427
    		//if rank unknown split string and take first word
428
    		if(genusOrUninomial == null){
429
    			String titleCache = taxon.getTitleCache();
430
    			String[] split = titleCache.split("\\s+");
431
    			for(String s:split){
432
    				genusOrUninomial = s;
433
    				break;
434
    			}
435
    		}
436
    		//if node has children
437

    
438
    		//retrieve list from map if not create List
439
    		if(sortedGenusMap.containsKey(genusOrUninomial)){
440
    			List<TaxonNode> list = sortedGenusMap.get(genusOrUninomial);
441
    			list.add(node);
442
    			sortedGenusMap.put(genusOrUninomial, list);
443
    		}else{
444
    			//create List for genus
445
    			List<TaxonNode> list = new ArrayList<TaxonNode>();
446
    			list.add(node);
447
    			sortedGenusMap.put(genusOrUninomial, list);
448
    		}
449
    	}
450
    	return sortedGenusMap;
451
    }
452

    
453
    /**
454
     *
455
     * creates new Classification and parent TaxonNodes at genus level
456
     *
457
     *
458
     * @param map GenusMap which holds a name (Genus) and all the same Taxa as a list
459
     * @param classification you want to improve the hierarchy (will not be modified)
460
     * @param configurator to change certain settings, if null then standard settings will be taken
461
     * @return new classification with parentNodes for each entry in the map
462
     */
463
    @SuppressWarnings({ "rawtypes", "unchecked" })
464
	@Transactional(readOnly = false)
465
	@Override
466
    public UpdateResult createHierarchyInClassification(Classification classification, CreateHierarchyForClassificationConfigurator configurator){
467
        UpdateResult result = new UpdateResult();
468
    	classification = dao.findByUuid(classification.getUuid());
469
    	Map<String, List<TaxonNode>> map = getSortedGenusList(classification.getAllNodes());
470

    
471
    	final String APPENDIX = "repaired";
472
    	String titleCache = org.apache.commons.lang.StringUtils.isBlank(classification.getTitleCache()) ? " " : classification.getTitleCache() ;
473
    	//TODO classification clone???
474
    	Classification newClassification = Classification.NewInstance(titleCache +" "+ APPENDIX);
475
    	newClassification.setReference(classification.getReference());
476

    
477
    	for(Map.Entry<String, List<TaxonNode>> entry:map.entrySet()){
478
    		String genus = entry.getKey();
479
    		List<TaxonNode> listOfTaxonNodes = entry.getValue();
480
    		TaxonNode parentNode = null;
481
    		//Search for genus in list
482
    		for(TaxonNode tNode:listOfTaxonNodes){
483
    			//take that taxonNode as parent and remove from list with all it possible children
484
    			//FIXME NPE for name
485
    			TaxonNameBase name = tNode.getTaxon().getName();
486
				NonViralName nonViralName = CdmBase.deproxy(name, NonViralName.class);
487
    			if(nonViralName.getNameCache().equalsIgnoreCase(genus)){
488
    				TaxonNode clone = (TaxonNode) tNode.clone();
489
    				if(!tNode.hasChildNodes()){
490
    					//FIXME remove classification
491
//    					parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference());
492
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
493
    					//remove taxonNode from list because just added to classification
494
    					result.addUpdatedObject(tNode);
495
    					listOfTaxonNodes.remove(tNode);
496
    				}else{
497
    					//get all childNodes
498
    					//save prior Hierarchy and remove them from the list
499
    					List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tNode, clone, result);
500
//    					parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference());
501
      					//FIXME remove classification
502
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
503
    					//remove taxonNode from list because just added to classification
504
    					result.addUpdatedObject(tNode);
505
    					listOfTaxonNodes.remove(tNode);
506
    					if(copyAllChildrenToTaxonNode != null){
507
    						listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
508
    					}
509
    				}
510
    				break;
511
    			}
512
    		}
513
    		if(parentNode == null){
514
    			//if no match found in list, create parentNode
515
    			NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
516
    			NonViralName nonViralName = parser.parseFullName(genus);
517
    			TaxonNameBase taxonNameBase = nonViralName;
518
    			//TODO Sec via configurator
519
    			Taxon taxon = Taxon.NewInstance(taxonNameBase, null);
520
    			parentNode = newClassification.addChildTaxon(taxon, 0, null, null);
521
    			result.addUpdatedObject(parentNode);
522
    		}
523
    		//iterate over the rest of the list
524
    		for(TaxonNode tn : listOfTaxonNodes){
525
    			//if TaxonNode has a parent and this is not the classification then skip it
526
    			//and add to new classification via the parentNode as children of it
527
    			//this should assures to keep the already existing hierarchy
528
    			//FIXME: Assert is not rootnode --> entrypoint is not classification in future but rather rootNode
529

    
530
    			if(!tn.isTopmostNode()){
531
    				continue; //skip to next taxonNode
532
    			}
533

    
534
    			TaxonNode clone = (TaxonNode) tn.clone();
535
    			//FIXME: citation from node
536
    			//TODO: addchildNode without citation and references
537
//    			TaxonNode taxonNode = parentNode.addChildNode(clone, classification.getCitation(), classification.getMicroReference());
538
    			TaxonNode taxonNode = parentNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
539
    			result.addUnChangedObject(clone);
540
    			if(tn.hasChildNodes()){
541
    				//save hierarchy in new classification
542
    				List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tn, taxonNode, result);
543
    				if(copyAllChildrenToTaxonNode != null){
544
    					listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
545
    				}
546
    			}
547
    		}
548
    	}
549
    	dao.saveOrUpdate(newClassification);
550
    	result.setCdmEntity(newClassification);
551
    	return result;
552
    }
553

    
554
    /**
555
     *
556
     * recursive method to get all childnodes of taxonNode in classification.
557
     *
558
     * @param classification just for References and Citation, can be null
559
     * @param copyFromNode TaxonNode with Children
560
     * @param copyToNode TaxonNode which will receive the children
561
     * @return List of ChildNode which has been added. If node has no children returns null
562
     */
563
   private List<TaxonNode> copyAllChildrenToTaxonNode(TaxonNode copyFromNode, TaxonNode copyToNode, UpdateResult result) {
564
		List<TaxonNode> childNodes;
565
		if(!copyFromNode.hasChildNodes()){
566
			return null;
567
		}else{
568
			childNodes = copyFromNode.getChildNodes();
569
		}
570
		for(TaxonNode childNode:childNodes){
571
			TaxonNode clone = (TaxonNode) childNode.clone();
572
			result.addUnChangedObject(clone);
573
			if(childNode.hasChildNodes()){
574
				copyAllChildrenToTaxonNode(childNode, clone, result);
575
			}
576
			//FIXME: citation from node instead of classification
577
//			copyToNode.addChildNode(clone,classification.getCitation(), classification.getMicroReference());
578
			copyToNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
579
		}
580
		return childNodes;
581
	}
582

    
583
   /**
584
     * {@inheritDoc}
585
     */
586
    @Override
587
   public ClassificationLookupDTO classificationLookup(Classification classification) {
588
       return dao.classificationLookup(classification);
589
   }
590

    
591

    
592
    public DeleteResult delete(UUID classificationUuid, TaxonDeletionConfigurator config){
593
        DeleteResult result = new DeleteResult();
594
        Classification classification = dao.findByUuid(classificationUuid);
595
        if (classification == null){
596
            result.addException(new IllegalArgumentException("The classification does not exist in database."));
597
            result.setAbort();
598
            return result;
599
        }
600
        if (!classification.hasChildNodes()){
601
            dao.delete(classification);
602
        }
603
        if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE) ){
604
            TaxonNode root = classification.getRootNode();
605
            taxonNodeDao.delete(root, true);
606
            dao.delete(classification);
607
        }
608

    
609

    
610
        return result;
611
    }
612

    
613
}
(7-7/97)