Project

General

Profile

Download (22.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 TaxonNode getTaxonNodeByUuid(UUID uuid) {
239
        return taxonNodeDao.findByUuid(uuid);
240
    }
241

    
242
    @Override
243
    public ITaxonTreeNode getTreeNodeByUuid(UUID uuid){
244
        ITaxonTreeNode treeNode = taxonNodeDao.findByUuid(uuid);
245
        if(treeNode == null){
246
            treeNode = dao.findByUuid(uuid);
247
        }
248

    
249
        return treeNode;
250
    }
251

    
252
    @Override
253
    public List<Classification> listClassifications(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
254
        return dao.list(limit, start, orderHints, propertyPaths);
255
    }
256

    
257
    @Override
258
    public UUID removeTaxonNode(TaxonNode taxonNode) {
259
        return taxonNodeDao.delete(taxonNode);
260
    }
261
    @Override
262
    public UUID removeTreeNode(ITaxonTreeNode treeNode) {
263
        if(treeNode instanceof Classification){
264
            return dao.delete((Classification) treeNode);
265
        }else if(treeNode instanceof TaxonNode){
266
            return taxonNodeDao.delete((TaxonNode)treeNode);
267
        }
268
        return null;
269
    }
270
    @Override
271
    public UUID saveTaxonNode(TaxonNode taxonNode) {
272
        return taxonNodeDao.save(taxonNode).getUuid();
273
    }
274

    
275
    @Override
276
    public Map<UUID, TaxonNode> saveTaxonNodeAll(
277
            Collection<TaxonNode> taxonNodeCollection) {
278
        return taxonNodeDao.saveAll(taxonNodeCollection);
279
    }
280

    
281
    @Override
282
    public UUID saveTreeNode(ITaxonTreeNode treeNode) {
283
        if(treeNode instanceof Classification){
284
            return dao.save((Classification) treeNode).getUuid();
285
        }else if(treeNode instanceof TaxonNode){
286
            return taxonNodeDao.save((TaxonNode)treeNode).getUuid();
287
        }
288
        return null;
289
    }
290

    
291
    @Override
292
    public List<TaxonNode> getAllNodes(){
293
        return taxonNodeDao.list(null,null);
294
    }
295

    
296
    @Override
297
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, List<UUID> excludeTaxa) {
298
        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid), excludeTaxa);
299
    }
300

    
301
    @Override
302
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, List<UUID> excludeTaxa) {
303
        return taxonDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, excludeTaxa);
304
    }
305

    
306
    @Override
307
    public List<UuidAndTitleCache<Classification>> getUuidAndTitleCache() {
308
        return dao.getUuidAndTitleCache();
309
    }
310

    
311
    @Override
312
    public Map<UUID, List<MediaRepresentation>> getAllMediaForChildNodes(
313
            TaxonNode taxonNode, List<String> propertyPaths, int size,
314
            int height, int widthOrDuration, String[] mimeTypes) {
315

    
316
        TreeMap<UUID, List<MediaRepresentation>> result = new TreeMap<UUID, List<MediaRepresentation>>();
317
        List<Media> taxonMedia = new ArrayList<Media>();
318
        List<MediaRepresentation> mediaRepresentations = new ArrayList<MediaRepresentation>();
319

    
320
        //add all media of the children to the result map
321
        if (taxonNode != null){
322

    
323
            List<TaxonNode> nodes = new ArrayList<TaxonNode>();
324

    
325
            nodes.add(loadTaxonNode(taxonNode, propertyPaths));
326
            nodes.addAll(loadChildNodesOfTaxonNode(taxonNode, propertyPaths));
327

    
328
            if (nodes != null){
329
                for(TaxonNode node : nodes){
330
                    Taxon taxon = node.getTaxon();
331
                    for (TaxonDescription taxonDescription: taxon.getDescriptions()){
332
                        for (DescriptionElementBase descriptionElement: taxonDescription.getElements()){
333
                            for(Media media : descriptionElement.getMedia()){
334
                                taxonMedia.add(media);
335

    
336
                                //find the best matching representation
337
                                mediaRepresentations.add(MediaUtils.findBestMatchingRepresentation(media,null, size, height, widthOrDuration, mimeTypes));
338

    
339
                            }
340
                        }
341
                    }
342
                    result.put(taxon.getUuid(), mediaRepresentations);
343

    
344
                }
345
            }
346

    
347
        }
348

    
349
        return result;
350

    
351
    }
352

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

    
357
        return getAllMediaForChildNodes(node, propertyPaths, size, height, widthOrDuration, mimeTypes);
358
    }
359

    
360
    @Override
361
    @Transactional(readOnly = false)
362
    public void updateTitleCache(Class<? extends Classification> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<Classification> cacheStrategy, IProgressMonitor monitor) {
363
        if (clazz == null){
364
            clazz = Classification.class;
365
        }
366
        super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
367
    }
368

    
369
    /**
370
     *
371
     * @param allNodesOfClassification
372
     * @return null - if  allNodesOfClassification is empty <br>
373
     */
374

    
375
    private Map<String, List<TaxonNode>> getSortedGenusList(Collection<TaxonNode> allNodesOfClassification){
376

    
377
    	if(allNodesOfClassification == null || allNodesOfClassification.isEmpty()){
378
    		return null;
379
    	}
380
    	Map<String, List<TaxonNode>> sortedGenusMap = new HashMap<String, List<TaxonNode>>();
381
    	for(TaxonNode node:allNodesOfClassification){
382
    		final TaxonNode tn = node;
383
    		Taxon taxon = node.getTaxon();
384
    		NonViralName name = CdmBase.deproxy(taxon.getName(), NonViralName.class);
385
    		String genusOrUninomial = name.getGenusOrUninomial();
386
    		//if rank unknown split string and take first word
387
    		if(genusOrUninomial == null){
388
    			String titleCache = taxon.getTitleCache();
389
    			String[] split = titleCache.split("\\s+");
390
    			for(String s:split){
391
    				genusOrUninomial = s;
392
    				break;
393
    			}
394
    		}
395
    		//if node has children
396

    
397
    		//retrieve list from map if not create List
398
    		if(sortedGenusMap.containsKey(genusOrUninomial)){
399
    			List<TaxonNode> list = sortedGenusMap.get(genusOrUninomial);
400
    			list.add(node);
401
    			sortedGenusMap.put(genusOrUninomial, list);
402
    		}else{
403
    			//create List for genus
404
    			List<TaxonNode> list = new ArrayList<TaxonNode>();
405
    			list.add(node);
406
    			sortedGenusMap.put(genusOrUninomial, list);
407
    		}
408
    	}
409
    	return sortedGenusMap;
410
    }
411

    
412
    /**
413
     *
414
     * creates new Classification and parent TaxonNodes at genus level
415
     *
416
     *
417
     * @param map GenusMap which holds a name (Genus) and all the same Taxa as a list
418
     * @param classification you want to improve the hierarchy (will not be modified)
419
     * @param configurator to change certain settings, if null then standard settings will be taken
420
     * @return new classification with parentNodes for each entry in the map
421
     */
422
    @SuppressWarnings({ "rawtypes", "unchecked" })
423
	@Transactional(readOnly = false)
424
	@Override
425
    public UpdateResult createHierarchyInClassification(Classification classification, CreateHierarchyForClassificationConfigurator configurator){
426
        UpdateResult result = new UpdateResult();
427
    	classification = dao.findByUuid(classification.getUuid());
428
    	Map<String, List<TaxonNode>> map = getSortedGenusList(classification.getAllNodes());
429

    
430
    	final String APPENDIX = "repaired";
431
    	String titleCache = org.apache.commons.lang.StringUtils.isBlank(classification.getTitleCache()) ? " " : classification.getTitleCache() ;
432
    	//TODO classification clone???
433
    	Classification newClassification = Classification.NewInstance(titleCache +" "+ APPENDIX);
434
    	newClassification.setReference(classification.getReference());
435

    
436
    	for(Map.Entry<String, List<TaxonNode>> entry:map.entrySet()){
437
    		String genus = entry.getKey();
438
    		List<TaxonNode> listOfTaxonNodes = entry.getValue();
439
    		TaxonNode parentNode = null;
440
    		//Search for genus in list
441
    		for(TaxonNode tNode:listOfTaxonNodes){
442
    			//take that taxonNode as parent and remove from list with all it possible children
443
    			//FIXME NPE for name
444
    			TaxonNameBase name = tNode.getTaxon().getName();
445
				NonViralName nonViralName = CdmBase.deproxy(name, NonViralName.class);
446
    			if(nonViralName.getNameCache().equalsIgnoreCase(genus)){
447
    				TaxonNode clone = (TaxonNode) tNode.clone();
448
    				if(!tNode.hasChildNodes()){
449
    					//FIXME remove classification
450
//    					parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference());
451
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
452
    					//remove taxonNode from list because just added to classification
453
    					result.addUpdatedObject(tNode);
454
    					listOfTaxonNodes.remove(tNode);
455
    				}else{
456
    					//get all childNodes
457
    					//save prior Hierarchy and remove them from the list
458
    					List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tNode, clone, result);
459
//    					parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference());
460
      					//FIXME remove classification
461
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
462
    					//remove taxonNode from list because just added to classification
463
    					result.addUpdatedObject(tNode);
464
    					listOfTaxonNodes.remove(tNode);
465
    					if(copyAllChildrenToTaxonNode != null){
466
    						listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
467
    					}
468
    				}
469
    				break;
470
    			}
471
    		}
472
    		if(parentNode == null){
473
    			//if no match found in list, create parentNode
474
    			NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
475
    			NonViralName nonViralName = parser.parseFullName(genus);
476
    			TaxonNameBase taxonNameBase = nonViralName;
477
    			//TODO Sec via configurator
478
    			Taxon taxon = Taxon.NewInstance(taxonNameBase, null);
479
    			parentNode = newClassification.addChildTaxon(taxon, 0, null, null);
480
    			result.addUpdatedObject(parentNode);
481
    		}
482
    		//iterate over the rest of the list
483
    		for(TaxonNode tn : listOfTaxonNodes){
484
    			//if TaxonNode has a parent and this is not the classification then skip it
485
    			//and add to new classification via the parentNode as children of it
486
    			//this should assures to keep the already existing hierarchy
487
    			//FIXME: Assert is not rootnode --> entrypoint is not classification in future but rather rootNode
488

    
489
    			if(!tn.isTopmostNode()){
490
    				continue; //skip to next taxonNode
491
    			}
492

    
493
    			TaxonNode clone = (TaxonNode) tn.clone();
494
    			//FIXME: citation from node
495
    			//TODO: addchildNode without citation and references
496
//    			TaxonNode taxonNode = parentNode.addChildNode(clone, classification.getCitation(), classification.getMicroReference());
497
    			TaxonNode taxonNode = parentNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
498
    			result.addUnChangedObject(clone);
499
    			if(tn.hasChildNodes()){
500
    				//save hierarchy in new classification
501
    				List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tn, taxonNode, result);
502
    				if(copyAllChildrenToTaxonNode != null){
503
    					listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
504
    				}
505
    			}
506
    		}
507
    	}
508
    	dao.saveOrUpdate(newClassification);
509
    	result.setCdmEntity(newClassification);
510
    	return result;
511
    }
512

    
513
    /**
514
     *
515
     * recursive method to get all childnodes of taxonNode in classification.
516
     *
517
     * @param classification just for References and Citation, can be null
518
     * @param copyFromNode TaxonNode with Children
519
     * @param copyToNode TaxonNode which will receive the children
520
     * @return List of ChildNode which has been added. If node has no children returns null
521
     */
522
   private List<TaxonNode> copyAllChildrenToTaxonNode(TaxonNode copyFromNode, TaxonNode copyToNode, UpdateResult result) {
523
		List<TaxonNode> childNodes;
524
		if(!copyFromNode.hasChildNodes()){
525
			return null;
526
		}else{
527
			childNodes = copyFromNode.getChildNodes();
528
		}
529
		for(TaxonNode childNode:childNodes){
530
			TaxonNode clone = (TaxonNode) childNode.clone();
531
			result.addUnChangedObject(clone);
532
			if(childNode.hasChildNodes()){
533
				copyAllChildrenToTaxonNode(childNode, clone, result);
534
			}
535
			//FIXME: citation from node instead of classification
536
//			copyToNode.addChildNode(clone,classification.getCitation(), classification.getMicroReference());
537
			copyToNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
538
		}
539
		return childNodes;
540
	}
541

    
542
}
(7-7/97)