Project

General

Profile

Download (24.6 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.pager.Pager;
31
import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
32
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
33
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
34
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
35
import eu.etaxonomy.cdm.model.common.CdmBase;
36
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
37
import eu.etaxonomy.cdm.model.description.TaxonDescription;
38
import eu.etaxonomy.cdm.model.media.Media;
39
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
40
import eu.etaxonomy.cdm.model.media.MediaUtils;
41
import eu.etaxonomy.cdm.model.name.NonViralName;
42
import eu.etaxonomy.cdm.model.name.Rank;
43
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
44
import eu.etaxonomy.cdm.model.taxon.Classification;
45
import eu.etaxonomy.cdm.model.taxon.ITaxonNodeComparator;
46
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
47
import eu.etaxonomy.cdm.model.taxon.Taxon;
48
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
49
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
50
import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;
51
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
52
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
53
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
54
import eu.etaxonomy.cdm.persistence.query.OrderHint;
55
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
56
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
57

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

    
68
    @Autowired
69
    private ITaxonNodeDao taxonNodeDao;
70

    
71
    @Autowired
72
    private ITaxonDao taxonDao;
73

    
74
    @Autowired
75
    private IBeanInitializer defaultBeanInitializer;
76

    
77
    @Override
78
    @Autowired
79
    protected void setDao(IClassificationDao dao) {
80
        this.dao = dao;
81
    }
82

    
83
    private Comparator<? super TaxonNode> taxonNodeComparator;
84

    
85
    @Autowired
86
    public void setTaxonNodeComparator(ITaxonNodeComparator<? super TaxonNode> taxonNodeComparator){
87
        this.taxonNodeComparator = (Comparator<? super TaxonNode>) taxonNodeComparator;
88
    }
89

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

    
95
        return loadTaxonNode(node.getUuid(), propertyPaths);
96
    }
97

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

    
104
    public TaxonNode loadTaxonNode(UUID taxonNodeUuid, List<String> propertyPaths){
105
        return taxonNodeDao.load(taxonNodeUuid, propertyPaths);
106
    }
107

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

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

    
120
        List<TaxonNode> results = new ArrayList<TaxonNode>();
121

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

    
126
            Integer remainingLimit = limit;
127
            int[] queryIndexes = rank == null ? new int[]{0} : new int[]{0,1};
128

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

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

    
154
    }
155

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

    
165
        TaxonNode thisNode = taxonNodeDao.load(taxonNode.getUuid(), propertyPaths);
166
        List<TaxonNode> pathToRoot = new ArrayList<TaxonNode>();
167
        pathToRoot.add(thisNode);
168

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

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

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

    
191
            pathToRoot.add(parentNode);
192
            thisNode = parentNode;
193
        }
194

    
195
        // initialize and invert order of nodes in list
196
        defaultBeanInitializer.initializeAll(pathToRoot, propertyPaths);
197
        Collections.reverse(pathToRoot);
198

    
199
        return pathToRoot;
200
    }
201

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

    
214

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

    
225
    @Override
226
    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
227
            Integer pageIndex, List<String> propertyPaths){
228

    
229
        Classification classification = dao.load(classificationUuid);
230
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
231

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

    
237
    @Override
238
    public Pager<TaxonNode> pageSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
239
            Integer pageIndex, List<String> propertyPaths){
240

    
241
        Classification classification = dao.load(classificationUuid);
242
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
243

    
244
        long numberOfResults = dao.countSiblingsOf(taxon, classification);
245

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

    
254
        return new DefaultPagerImpl<TaxonNode>(pageIndex, numberOfResults, pageSize, results);
255
    }
256

    
257
    @Override
258
    public List<TaxonNode> listSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, Integer pageSize,
259
            Integer pageIndex, List<String> propertyPaths){
260

    
261
        Pager<TaxonNode> pager = pageSiblingsOfTaxon(taxonUuid, classificationUuid, pageSize, pageIndex, propertyPaths);
262
        return pager.getRecords();
263
    }
264

    
265
    @Override
266
    public TaxonNode getTaxonNodeByUuid(UUID uuid) {
267
        return taxonNodeDao.findByUuid(uuid);
268
    }
269

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

    
277
        return treeNode;
278
    }
279

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

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

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

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

    
319
    @Override
320
    public List<TaxonNode> getAllNodes(){
321
        return taxonNodeDao.list(null,null);
322
    }
323

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

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

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

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

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

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

    
354
        TreeMap<UUID, List<MediaRepresentation>> result = new TreeMap<UUID, List<MediaRepresentation>>();
355
        List<Media> taxonMedia = new ArrayList<Media>();
356
        List<MediaRepresentation> mediaRepresentations = new ArrayList<MediaRepresentation>();
357

    
358
        //add all media of the children to the result map
359
        if (taxonNode != null){
360

    
361
            List<TaxonNode> nodes = new ArrayList<TaxonNode>();
362

    
363
            nodes.add(loadTaxonNode(taxonNode, propertyPaths));
364
            nodes.addAll(loadChildNodesOfTaxonNode(taxonNode, propertyPaths));
365

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

    
374
                                //find the best matching representation
375
                                mediaRepresentations.add(MediaUtils.findBestMatchingRepresentation(media,null, size, height, widthOrDuration, mimeTypes));
376

    
377
                            }
378
                        }
379
                    }
380
                    result.put(taxon.getUuid(), mediaRepresentations);
381

    
382
                }
383
            }
384

    
385
        }
386

    
387
        return result;
388

    
389
    }
390

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

    
395
        return getAllMediaForChildNodes(node, propertyPaths, size, height, widthOrDuration, mimeTypes);
396
    }
397

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

    
407
    /**
408
     *
409
     * @param allNodesOfClassification
410
     * @return null - if  allNodesOfClassification is empty <br>
411
     */
412

    
413
    private Map<String, List<TaxonNode>> getSortedGenusList(Collection<TaxonNode> allNodesOfClassification){
414

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

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

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

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

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

    
527
    			if(!tn.isTopmostNode()){
528
    				continue; //skip to next taxonNode
529
    			}
530

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

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

    
580
}
(7-7/97)