Project

General

Profile

Download (44.6 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.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.Comparator;
17
import java.util.HashMap;
18
import java.util.HashSet;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.Set;
22
import java.util.TreeMap;
23
import java.util.UUID;
24

    
25
import javax.persistence.EntityNotFoundException;
26

    
27
import org.apache.commons.collections.CollectionUtils;
28
import org.apache.commons.lang.StringUtils;
29
import org.apache.log4j.Logger;
30
import org.springframework.beans.factory.annotation.Autowired;
31
import org.springframework.stereotype.Service;
32
import org.springframework.transaction.annotation.Transactional;
33

    
34
import eu.etaxonomy.cdm.api.service.config.CreateHierarchyForClassificationConfigurator;
35
import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;
36
import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
37
import eu.etaxonomy.cdm.api.service.dto.EntityDTO;
38
import eu.etaxonomy.cdm.api.service.dto.GroupedTaxonDTO;
39
import eu.etaxonomy.cdm.api.service.dto.MarkedEntityDTO;
40
import eu.etaxonomy.cdm.api.service.dto.TaxonInContextDTO;
41
import eu.etaxonomy.cdm.api.service.pager.Pager;
42
import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
43
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
44
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
45
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
46
import eu.etaxonomy.cdm.exception.FilterException;
47
import eu.etaxonomy.cdm.exception.UnpublishedException;
48
import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
49
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
50
import eu.etaxonomy.cdm.model.common.CdmBase;
51
import eu.etaxonomy.cdm.model.common.ITreeNode;
52
import eu.etaxonomy.cdm.model.common.MarkerType;
53
import eu.etaxonomy.cdm.model.common.TreeIndex;
54
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
55
import eu.etaxonomy.cdm.model.description.TaxonDescription;
56
import eu.etaxonomy.cdm.model.media.Media;
57
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
58
import eu.etaxonomy.cdm.model.media.MediaUtils;
59
import eu.etaxonomy.cdm.model.name.INonViralName;
60
import eu.etaxonomy.cdm.model.name.Rank;
61
import eu.etaxonomy.cdm.model.name.TaxonName;
62
import eu.etaxonomy.cdm.model.reference.Reference;
63
import eu.etaxonomy.cdm.model.taxon.Classification;
64
import eu.etaxonomy.cdm.model.taxon.ITaxonNodeComparator;
65
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
66
import eu.etaxonomy.cdm.model.taxon.Synonym;
67
import eu.etaxonomy.cdm.model.taxon.Taxon;
68
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
69
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
70
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
71
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
72
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
73
import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;
74
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
75
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
76
import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
77
import eu.etaxonomy.cdm.persistence.dto.ClassificationLookupDTO;
78
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
79
import eu.etaxonomy.cdm.persistence.dto.TaxonStatus;
80
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
81
import eu.etaxonomy.cdm.persistence.query.OrderHint;
82
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
83
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
84

    
85
/**
86
 * @author n.hoffmann
87
 * @since Sep 21, 2009
88
 */
89
@Service
90
@Transactional(readOnly = true)
91
public class ClassificationServiceImpl
92
             extends IdentifiableServiceBase<Classification, IClassificationDao>
93
             implements IClassificationService {
94

    
95
    private static final Logger logger = Logger.getLogger(ClassificationServiceImpl.class);
96

    
97
    @Autowired
98
    private ITaxonNodeDao taxonNodeDao;
99

    
100
    @Autowired
101
    private ITaxonDao taxonDao;
102

    
103
    @Autowired
104
    private ITaxonNodeService taxonNodeService;
105

    
106
    @Autowired
107
    private IDefinedTermDao termDao;
108

    
109
    @Autowired
110
    private IBeanInitializer defaultBeanInitializer;
111

    
112
    @Override
113
    @Autowired
114
    protected void setDao(IClassificationDao dao) {
115
        this.dao = dao;
116
    }
117

    
118
    private Comparator<? super TaxonNode> taxonNodeComparator;
119

    
120
    @Autowired
121
    public void setTaxonNodeComparator(ITaxonNodeComparator<? super TaxonNode> taxonNodeComparator){
122
        this.taxonNodeComparator = (Comparator<? super TaxonNode>) taxonNodeComparator;
123
    }
124

    
125
    @Override
126
    public TaxonNode loadTaxonNodeByTaxon(Taxon taxon, UUID classificationUuid, List<String> propertyPaths){
127
        Classification tree = dao.load(classificationUuid);
128
        TaxonNode node = tree.getNode(taxon);
129

    
130
        return loadTaxonNode(node.getUuid(), propertyPaths);
131
    }
132

    
133
    public TaxonNode loadTaxonNode(UUID taxonNodeUuid, List<String> propertyPaths){
134
        return taxonNodeDao.load(taxonNodeUuid, propertyPaths);
135
    }
136

    
137
    @Override
138
    @Transactional(readOnly = false)
139
    public UpdateResult cloneClassification(UUID classificationUuid,
140
    		String name, Reference sec, TaxonRelationshipType relationshipType) {
141
        UpdateResult result = new UpdateResult();
142
    	Classification classification = load(classificationUuid);
143
    	Classification clone = Classification.NewInstance(name);
144
    	clone.setReference(sec);
145

    
146
    	//clone taxa and taxon nodes
147
    	List<TaxonNode> childNodes = classification.getRootNode().getChildNodes();
148
    	for (TaxonNode taxonNode : childNodes) {
149
    		addChildTaxa(taxonNode, null, clone, relationshipType);
150
    	}
151
    	dao.saveOrUpdate(clone);
152
    	result.setCdmEntity(clone);
153
    	return result;
154
    }
155

    
156
    private void addChildTaxa(TaxonNode originalParentNode, TaxonNode cloneParentNode, Classification classification, TaxonRelationshipType relationshipType){
157
        Reference reference = classification.getReference();
158
    	Taxon cloneTaxon = (Taxon) HibernateProxyHelper.deproxy(originalParentNode.getTaxon(), Taxon.class).clone();
159
    	cloneTaxon.setSec(reference);
160
		String microReference = null;
161
		List<TaxonNode> originalChildNodes = originalParentNode.getChildNodes();
162
		HHH_9751_Util.removeAllNull(originalChildNodes);
163

    
164
		//add relation between taxa
165
		if (relationshipType != null){
166
		    cloneTaxon.addTaxonRelation(originalParentNode.getTaxon(), relationshipType, reference, microReference);
167
		}
168

    
169
		TaxonNode cloneChildNode = null;
170
    	//add taxon node to either parent node or classification (no parent node)
171
    	if(cloneParentNode==null){
172
    		cloneChildNode = classification.addChildTaxon(cloneTaxon, reference, microReference);
173
    	}
174
    	else{
175
    		cloneChildNode = cloneParentNode.addChildTaxon(cloneTaxon, reference, microReference);
176
    	}
177
    	taxonNodeDao.saveOrUpdate(cloneChildNode);
178
    	//add children
179
		for (TaxonNode originalChildNode : originalChildNodes) {
180
    		addChildTaxa(originalChildNode, cloneChildNode, classification, relationshipType);
181
    	}
182
    }
183

    
184
    @Override
185
    public List<TaxonNode> listRankSpecificRootNodes(Classification classification,
186
            TaxonNode subtree, Rank rank,
187
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
188
        return pageRankSpecificRootNodes(classification, subtree, rank, includeUnpublished, pageSize, pageIndex, propertyPaths).getRecords();
189
    }
190

    
191
    @Override
192
    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, Rank rank,
193
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
194
        return pageRankSpecificRootNodes(classification, null, rank, includeUnpublished, pageSize, pageIndex, propertyPaths);
195
    }
196

    
197
    @Override
198
    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, TaxonNode subtree, Rank rank,
199
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
200
        long[] numberOfResults = dao.countRankSpecificRootNodes(classification, subtree, includeUnpublished, rank);
201
        long totalNumberOfResults = numberOfResults[0] + (numberOfResults.length > 1 ? numberOfResults[1] : 0);
202

    
203
        List<TaxonNode> results = new ArrayList<>();
204

    
205
        if (AbstractPagerImpl.hasResultsInRange(totalNumberOfResults, pageIndex, pageSize)) { // no point checking again
206
            Integer limit = PagerUtils.limitFor(pageSize);
207
            Integer start = PagerUtils.startFor(pageSize, pageIndex);
208

    
209
            Integer remainingLimit = limit;
210
            int[] queryIndexes = rank == null ? new int[]{0} : new int[]{0,1};
211

    
212
            for(int queryIndex: queryIndexes) {
213
                if(start != null && start > numberOfResults[queryIndex]) {
214
                    // start in next query with new start value
215
                    start = start - (int)numberOfResults[queryIndex];
216
                    continue;
217
                }
218

    
219
                List<TaxonNode> perQueryResults = dao.listRankSpecificRootNodes(classification,
220
                        subtree, rank, includeUnpublished, remainingLimit,
221
                        start, propertyPaths, queryIndex);
222
                results.addAll(perQueryResults);
223
                if(remainingLimit != null ){
224
                    remainingLimit = remainingLimit - results.size();
225
                    if(remainingLimit <= 0) {
226
                        // no need to run further queries if first query returned enough items!
227
                        break;
228
                    }
229
                    // start at with fist item of next query to fetch the remaining items
230
                    start = 0;
231
                }
232
            }
233
        }
234
//        long start_t = System.currentTimeMillis();
235
        Collections.sort(results, taxonNodeComparator); // TODO is ordering during the hibernate query in the dao possible?
236
//        System.err.println("service.pageRankSpecificRootNodes() - Collections.sort(results,  taxonNodeComparator) " + (System.currentTimeMillis() - start_t));
237
        return new DefaultPagerImpl<>(pageIndex, totalNumberOfResults, pageSize, results);
238

    
239
    }
240

    
241
    @Override
242
    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, Rank baseRank,
243
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
244
        return loadTreeBranch(taxonNode, null, baseRank, includeUnpublished, propertyPaths);
245
    }
246

    
247
    /**
248
     * {@inheritDoc}
249
     */
250
    @Override
251
    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, TaxonNode subtree, Rank baseRank,
252
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
253

    
254
        TaxonNode thisNode = taxonNodeDao.load(taxonNode.getUuid(), propertyPaths);
255
        if(baseRank != null){
256
            baseRank = (Rank) termDao.load(baseRank.getUuid());
257
        }
258
        if (!includeUnpublished && thisNode.getTaxon() != null && !thisNode.getTaxon().isPublish()){
259
            throw new UnpublishedException("Final taxon in tree branch is unpublished.");
260
        }
261

    
262
        List<TaxonNode> pathToRoot = new ArrayList<>();
263
        pathToRoot.add(thisNode);
264

    
265
        while(!thisNode.isTopmostNode()){
266
            //TODO why do we need to deproxy here?
267
            //     without this thisNode.getParent() will return NULL in
268
            //     some cases (environment dependend?) even if the parent exits
269
            TaxonNode parentNode = CdmBase.deproxy(thisNode).getParent();
270

    
271
            if(parentNode == null){
272
                throw new NullPointerException("Taxon node " + thisNode + " must have a parent since it is not top most");
273
            }
274
            if(parentNode.getTaxon() == null){
275
                throw new NullPointerException("The taxon associated with taxon node " + parentNode + " is NULL");
276
            }
277
            if(!includeUnpublished && !parentNode.getTaxon().isPublish()){
278
                throw new UnpublishedException("Some taxon in tree branch is unpublished.");
279
            }
280
            if(parentNode.getTaxon().getName() == null){
281
                throw new NullPointerException("The name of the taxon associated with taxonNode " + parentNode + " is NULL");
282
            }
283

    
284
            Rank parentNodeRank = (parentNode.getTaxon().getName() == null) ? null : parentNode.getTaxon().getName().getRank();
285
            // stop if the next parent is higher than the baseRank
286
            if(baseRank != null && parentNodeRank != null && baseRank.isLower(parentNodeRank)){
287
                break;
288
            }
289
            if((subtree!= null && !subtree.isAncestor(parentNode) )){
290
                break;
291
            }
292

    
293
            pathToRoot.add(parentNode);
294
            thisNode = parentNode;
295
        }
296

    
297
        // initialize and invert order of nodes in list
298
        defaultBeanInitializer.initializeAll(pathToRoot, propertyPaths);
299
        Collections.reverse(pathToRoot);
300

    
301
        return pathToRoot;
302
    }
303

    
304
    @Override
305
    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification, Rank baseRank,
306
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
307
        return loadTreeBranchToTaxon(taxon, classification, null, baseRank, includeUnpublished, propertyPaths);
308
    }
309

    
310
    @Override
311
    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification,
312
            TaxonNode subtree, Rank baseRank,
313
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
314

    
315
        UUID nodeUuid = getTaxonNodeUuidByTaxonUuid(classification.getUuid(), taxon.getUuid());
316
        TaxonNode node = taxonNodeService.find(nodeUuid);
317
        if(node == null){
318
            logger.warn("The specified taxon is not found in the given tree.");
319
            return null;
320
        }else if (subtree != null && !node.isDescendant(subtree)){
321
            //TODO handle as exception? E.g. FilterException, AccessDeniedException?
322
            logger.warn("The specified taxon is not found for the given subtree.");
323
            return null;
324
        }
325

    
326
        return loadTreeBranch(node, subtree, baseRank, includeUnpublished, propertyPaths);
327
    }
328

    
329

    
330
    @Override
331
    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
332
            List<String> propertyPaths) {
333
        taxonNode = taxonNodeDao.load(taxonNode.getUuid());
334
        List<TaxonNode> childNodes = new ArrayList<TaxonNode>(taxonNode.getChildNodes());
335
        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
336
        Collections.sort(childNodes, taxonNodeComparator);
337
        return childNodes;
338
    }
339

    
340
    @Override
341
    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid,
342
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths){
343
        try {
344
            return listChildNodesOfTaxon(taxonUuid, classificationUuid, null, includeUnpublished, pageSize, pageIndex, propertyPaths);
345
        } catch (FilterException e) {
346
            throw new RuntimeException(e);  //this should not happen as filter is null
347
        }
348
    }
349

    
350
    @Override
351
    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid, UUID subtreeUuid,
352
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) throws FilterException{
353

    
354
        Classification classification = dao.load(classificationUuid);
355
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
356
        TaxonNode subtree = taxonNodeDao.load(subtreeUuid);
357
        if (subtreeUuid != null && subtree == null){
358
            throw new FilterException("Taxon node for subtree filter can not be found in database", true);
359
        }
360

    
361
        List<TaxonNode> results = dao.listChildrenOf(
362
                taxon, classification, subtree, includeUnpublished, pageSize, pageIndex, propertyPaths);
363
        Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
364
        return results;
365
    }
366

    
367
    @Override
368
    public Pager<TaxonNode> pageSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, boolean includeUnpublished,
369
            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
370

    
371
        Classification classification = dao.load(classificationUuid);
372
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
373

    
374
        long numberOfResults = dao.countSiblingsOf(taxon, classification, includeUnpublished);
375

    
376
        List<TaxonNode> results;
377
        if(PagerUtils.hasResultsInRange(numberOfResults, pageIndex, pageSize)) {
378
            results = dao.listSiblingsOf(taxon, classification, includeUnpublished, pageSize, pageIndex, propertyPaths);
379
            Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
380
        } else {
381
            results = new ArrayList<>();
382
        }
383

    
384
        return new DefaultPagerImpl<>(pageIndex, numberOfResults, pageSize, results);
385
    }
386

    
387
    @Override
388
    public List<TaxonNode> listSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, boolean includeUnpublished,
389
            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
390

    
391
        Pager<TaxonNode> pager = pageSiblingsOfTaxon(taxonUuid, classificationUuid, includeUnpublished, pageSize, pageIndex, propertyPaths);
392
        return pager.getRecords();
393
    }
394

    
395
    @Override
396
    public ITaxonTreeNode getTreeNodeByUuid(UUID uuid){
397
        ITaxonTreeNode treeNode = taxonNodeDao.findByUuid(uuid);
398
        if(treeNode == null){
399
            treeNode = dao.findByUuid(uuid);
400
        }
401

    
402
        return treeNode;
403
    }
404

    
405
    @Override
406
    public TaxonNode getRootNode(UUID classificationUuid){
407
        return dao.getRootNode(classificationUuid);
408
    }
409

    
410
    @Override
411
    public List<Classification> listClassifications(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
412
        return dao.list(limit, start, orderHints, propertyPaths);
413
    }
414

    
415
    @Override
416
    public UUID removeTaxonNode(TaxonNode taxonNode) {
417
        return taxonNodeDao.delete(taxonNode);
418
    }
419
    @Override
420
    public UUID removeTreeNode(ITaxonTreeNode treeNode) {
421
        if(treeNode instanceof Classification){
422
            return dao.delete((Classification) treeNode);
423
        }else if(treeNode instanceof TaxonNode){
424
            return taxonNodeDao.delete((TaxonNode)treeNode);
425
        }
426
        return null;
427
    }
428
    @Override
429
    public UUID saveTaxonNode(TaxonNode taxonNode) {
430
        return taxonNodeDao.save(taxonNode).getUuid();
431
    }
432

    
433
    @Override
434
    public Map<UUID, TaxonNode> saveTaxonNodeAll(
435
            Collection<TaxonNode> taxonNodeCollection) {
436
        return taxonNodeDao.saveAll(taxonNodeCollection);
437
    }
438

    
439
    @Override
440
    public UUID saveClassification(Classification classification) {
441

    
442
       taxonNodeDao.saveOrUpdateAll(classification.getAllNodes());
443
       UUID result =dao.saveOrUpdate(classification);
444
       return result;
445
    }
446

    
447
    @Override
448
    public UUID saveTreeNode(ITaxonTreeNode treeNode) {
449
        if(treeNode instanceof Classification){
450
            return dao.save((Classification) treeNode).getUuid();
451
        }else if(treeNode instanceof TaxonNode){
452
            return taxonNodeDao.save((TaxonNode)treeNode).getUuid();
453
        }
454
        return null;
455
    }
456

    
457
    @Override
458
    public List<TaxonNode> getAllNodes(){
459
        return taxonNodeDao.list(null,null);
460
    }
461

    
462
    @Override
463
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, Integer limit, String pattern, boolean searchForClassifications) {
464
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid),  limit, pattern, searchForClassifications);
465
    }
466

    
467
    @Override
468
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification,  Integer limit, String pattern, boolean searchForClassifications) {
469
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification,  limit, pattern, searchForClassifications);
470
    }
471

    
472
    @Override
473
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, boolean searchForClassifications ) {
474
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid), null, null, searchForClassifications);
475
    }
476

    
477
    @Override
478
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, boolean searchForClassifications ) {
479
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, null, null, searchForClassifications);
480
    }
481

    
482
    @Override
483
    public List<UuidAndTitleCache<Classification>> getUuidAndTitleCache(Integer limit, String pattern) {
484
        return dao.getUuidAndTitleCache(limit, pattern);
485
    }
486

    
487
    @Override
488
    public Map<UUID, List<MediaRepresentation>> getAllMediaForChildNodes(
489
            TaxonNode taxonNode, List<String> propertyPaths, int size,
490
            int height, int widthOrDuration, String[] mimeTypes) {
491

    
492
        TreeMap<UUID, List<MediaRepresentation>> result = new TreeMap<>();
493
        List<MediaRepresentation> mediaRepresentations = new ArrayList<>();
494

    
495
        //add all media of the children to the result map
496
        if (taxonNode != null){
497

    
498
            List<TaxonNode> nodes = new ArrayList<>();
499

    
500
            nodes.add(loadTaxonNode(taxonNode.getUuid(), propertyPaths));
501
            nodes.addAll(loadChildNodesOfTaxonNode(taxonNode, propertyPaths));
502

    
503
            for(TaxonNode node : nodes){
504
                Taxon taxon = node.getTaxon();
505
                for (TaxonDescription taxonDescription: taxon.getDescriptions()){
506
                    for (DescriptionElementBase descriptionElement: taxonDescription.getElements()){
507
                        for(Media media : descriptionElement.getMedia()){
508
                            //find the best matching representation
509
                            mediaRepresentations.add(MediaUtils.findBestMatchingRepresentation(media,null, size, height, widthOrDuration, mimeTypes));
510
                        }
511
                    }
512
                }
513
                result.put(taxon.getUuid(), mediaRepresentations);
514
            }
515
        }
516

    
517
        return result;
518
    }
519

    
520
    @Override
521
    @Transactional(readOnly = false)
522
    public UpdateResult updateCaches(Class<? extends Classification> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<Classification> cacheStrategy, IProgressMonitor monitor) {
523
        if (clazz == null){
524
            clazz = Classification.class;
525
        }
526
        return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
527
    }
528

    
529
    /**
530
     *
531
     * @param allNodesOfClassification
532
     * @return null - if  allNodesOfClassification is empty <br>
533
     */
534

    
535
    private Map<String, List<TaxonNode>> getSortedGenusList(Collection<TaxonNode> allNodesOfClassification){
536

    
537
    	if(allNodesOfClassification == null || allNodesOfClassification.isEmpty()){
538
    		return null;
539
    	}
540
    	Map<String, List<TaxonNode>> sortedGenusMap = new HashMap<>();
541
    	for(TaxonNode node:allNodesOfClassification){
542
    		Taxon taxon = node.getTaxon();
543
    		INonViralName name = taxon.getName();
544
    		String genusOrUninomial = name.getGenusOrUninomial();
545
    		//if rank unknown split string and take first word
546
    		if(genusOrUninomial == null){
547
    			String titleCache = taxon.getTitleCache();
548
    			String[] split = titleCache.split("\\s+");
549
    			for(String s:split){
550
    				genusOrUninomial = s;
551
    				break;
552
    			}
553
    		}
554
    		//if node has children
555

    
556
    		//retrieve list from map if not create List
557
    		if(sortedGenusMap.containsKey(genusOrUninomial)){
558
    			List<TaxonNode> list = sortedGenusMap.get(genusOrUninomial);
559
    			list.add(node);
560
    			sortedGenusMap.put(genusOrUninomial, list);
561
    		}else{
562
    			//create List for genus
563
    			List<TaxonNode> list = new ArrayList<>();
564
    			list.add(node);
565
    			sortedGenusMap.put(genusOrUninomial, list);
566
    		}
567
    	}
568
    	return sortedGenusMap;
569
    }
570

    
571
    /**
572
     *
573
     * creates new Classification and parent TaxonNodes at genus level
574
     *
575
     *
576
     * @param map GenusMap which holds a name (Genus) and all the same Taxa as a list
577
     * @param classification you want to improve the hierarchy (will not be modified)
578
     * @param configurator to change certain settings, if null then standard settings will be taken
579
     * @return new classification with parentNodes for each entry in the map
580
     */
581
    @SuppressWarnings({ "unchecked" })
582
	@Transactional(readOnly = false)
583
	@Override
584
    public UpdateResult createHierarchyInClassification(Classification classification, CreateHierarchyForClassificationConfigurator configurator){
585
        UpdateResult result = new UpdateResult();
586
    	classification = dao.findByUuid(classification.getUuid());
587
    	Map<String, List<TaxonNode>> map = getSortedGenusList(classification.getAllNodes());
588

    
589
    	final String APPENDIX = "repaired";
590
    	String titleCache = StringUtils.isBlank(classification.getTitleCache()) ? " " : classification.getTitleCache() ;
591
    	//TODO classification clone???
592
    	Classification newClassification = Classification.NewInstance(titleCache +" "+ APPENDIX);
593
    	newClassification.setReference(classification.getReference());
594

    
595
    	for(Map.Entry<String, List<TaxonNode>> entry:map.entrySet()){
596
    		String genus = entry.getKey();
597
    		List<TaxonNode> listOfTaxonNodes = entry.getValue();
598
    		TaxonNode parentNode = null;
599
    		//Search for genus in list
600
    		for(TaxonNode tNode:listOfTaxonNodes){
601
    			//take that taxonNode as parent and remove from list with all it possible children
602
    			//FIXME NPE for name
603
    			TaxonName name = tNode.getTaxon().getName();
604
    			if(name.getNameCache().equalsIgnoreCase(genus)){
605
    				TaxonNode clone = (TaxonNode) tNode.clone();
606
    				if(!tNode.hasChildNodes()){
607
    					//FIXME remove classification
608
//    					parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference());
609
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
610
    					//remove taxonNode from list because just added to classification
611
    					result.addUpdatedObject(tNode);
612
    					listOfTaxonNodes.remove(tNode);
613
    				}else{
614
    					//get all childNodes
615
    					//save prior Hierarchy and remove them from the list
616
    					List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tNode, clone, result);
617
//    					parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference());
618
      					//FIXME remove classification
619
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
620
    					//remove taxonNode from list because just added to classification
621
    					result.addUpdatedObject(tNode);
622
    					listOfTaxonNodes.remove(tNode);
623
    					if(copyAllChildrenToTaxonNode != null){
624
    						listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
625
    					}
626
    				}
627
    				break;
628
    			}
629
    		}
630
    		if(parentNode == null){
631
    			//if no match found in list, create parentNode
632
    			NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
633
    			TaxonName TaxonName = (TaxonName)parser.parseFullName(genus);
634
    			//TODO Sec via configurator
635
    			Taxon taxon = Taxon.NewInstance(TaxonName, null);
636
    			parentNode = newClassification.addChildTaxon(taxon, 0, null, null);
637
    			result.addUpdatedObject(parentNode);
638
    		}
639
    		//iterate over the rest of the list
640
    		for(TaxonNode tn : listOfTaxonNodes){
641
    			//if TaxonNode has a parent and this is not the classification then skip it
642
    			//and add to new classification via the parentNode as children of it
643
    			//this should assures to keep the already existing hierarchy
644
    			//FIXME: Assert is not rootnode --> entrypoint is not classification in future but rather rootNode
645

    
646
    			if(!tn.isTopmostNode()){
647
    				continue; //skip to next taxonNode
648
    			}
649

    
650
    			TaxonNode clone = (TaxonNode) tn.clone();
651
    			//FIXME: citation from node
652
    			//TODO: addchildNode without citation and references
653
//    			TaxonNode taxonNode = parentNode.addChildNode(clone, classification.getCitation(), classification.getMicroReference());
654
    			TaxonNode taxonNode = parentNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
655
    			result.addUnChangedObject(clone);
656
    			if(tn.hasChildNodes()){
657
    				//save hierarchy in new classification
658
    				List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tn, taxonNode, result);
659
    				if(copyAllChildrenToTaxonNode != null){
660
    					listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
661
    				}
662
    			}
663
    		}
664
    	}
665
    	dao.saveOrUpdate(newClassification);
666
    	result.setCdmEntity(newClassification);
667
    	return result;
668
    }
669

    
670
    /**
671
     *
672
     * recursive method to get all childnodes of taxonNode in classification.
673
     *
674
     * @param classification just for References and Citation, can be null
675
     * @param copyFromNode TaxonNode with Children
676
     * @param copyToNode TaxonNode which will receive the children
677
     * @return List of ChildNode which has been added. If node has no children returns null
678
     */
679
   private List<TaxonNode> copyAllChildrenToTaxonNode(TaxonNode copyFromNode, TaxonNode copyToNode, UpdateResult result) {
680
		List<TaxonNode> childNodes;
681
		if(!copyFromNode.hasChildNodes()){
682
			return null;
683
		}else{
684
			childNodes = copyFromNode.getChildNodes();
685
		}
686
		for(TaxonNode childNode:childNodes){
687
			TaxonNode clone = (TaxonNode) childNode.clone();
688
			result.addUnChangedObject(clone);
689
			if(childNode.hasChildNodes()){
690
				copyAllChildrenToTaxonNode(childNode, clone, result);
691
			}
692
			//FIXME: citation from node instead of classification
693
//			copyToNode.addChildNode(clone,classification.getCitation(), classification.getMicroReference());
694
			copyToNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
695
		}
696
		return childNodes;
697
	}
698

    
699
    @Override
700
    public ClassificationLookupDTO classificationLookup(Classification classification) {
701
        return dao.classificationLookup(classification);
702
    }
703

    
704
    @Override
705
    @Transactional
706
    public DeleteResult delete(UUID classificationUuid, TaxonDeletionConfigurator config){
707
        DeleteResult result = new DeleteResult();
708
        Classification classification = dao.findByUuid(classificationUuid);
709
        if (classification == null){
710
            result.addException(new IllegalArgumentException("The classification does not exist in database."));
711
            result.setAbort();
712
            return result;
713
        }
714
        if (!classification.hasChildNodes()){
715
            dao.delete(classification);
716
            result.addDeletedObject(classification);
717
            return result;
718
        }
719
        if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)){
720
//            TaxonNode root = classification.getRootNode();
721
//            result.includeResult(taxonNodeService.deleteTaxonNode(HibernateProxyHelper.deproxy(root), config));
722
//            result.addDeletedObject(classification);
723
            dao.delete(classification);
724
            result.addDeletedObject(classification);
725
            return result;
726
        }
727

    
728

    
729
        return result;
730
    }
731

    
732
    @Override
733
    public List<GroupedTaxonDTO> groupTaxaByHigherTaxon(List<UUID> originalTaxonUuids, UUID classificationUuid, Rank minRank, Rank maxRank){
734
        List<GroupedTaxonDTO> result = new ArrayList<>();
735

    
736
        //get treeindex for each taxonUUID
737
        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
738

    
739
        //build treeindex list (or tree)
740
        //TODO make it work with TreeIndex or move there
741
        List<String> treeIndexClosureStr = new ArrayList<>();
742
        for (TreeIndex treeIndex : taxonIdTreeIndexMap.values()){
743
            String[] splits = treeIndex.toString().substring(1).split(ITreeNode.separator);
744
            String currentIndex = ITreeNode.separator;
745
            for (String split : splits){
746
                if (split.equals("")){
747
                    continue;
748
                }
749
                currentIndex += split + ITreeNode.separator;
750
                if (!treeIndexClosureStr.contains(currentIndex) && !split.startsWith(ITreeNode.treePrefix)){
751
                    treeIndexClosureStr.add(currentIndex);
752
                }
753
            }
754
        }
755

    
756
        //get rank sortindex for all parent taxa with sortindex <= minRank and sortIndex >= maxRank (if available)
757
        Integer minRankOrderIndex = minRank == null ? null : minRank.getOrderIndex();
758
        Integer maxRankOrderIndex = maxRank == null ? null : maxRank.getOrderIndex();
759
        List<TreeIndex> treeIndexClosure = TreeIndex.NewListInstance(treeIndexClosureStr);
760

    
761
        Map<TreeIndex, Integer> treeIndexSortIndexMapTmp = taxonNodeDao.rankOrderIndexForTreeIndex(treeIndexClosure, minRankOrderIndex, maxRankOrderIndex);
762

    
763
        //remove all treeindex with "exists child in above map(and child.sortindex > xxx)
764
        List<TreeIndex> treeIndexList = TreeIndex.sort(treeIndexSortIndexMapTmp.keySet());
765

    
766
        Map<TreeIndex, Integer> treeIndexSortIndexMap = new HashMap<>();
767
        TreeIndex lastTreeIndex = null;
768
        for (TreeIndex treeIndex : treeIndexList){
769
            if (lastTreeIndex != null && lastTreeIndex.hasChild(treeIndex)){
770
                treeIndexSortIndexMap.remove(lastTreeIndex);
771
            }
772
            treeIndexSortIndexMap.put(treeIndex, treeIndexSortIndexMapTmp.get(treeIndex));
773
            lastTreeIndex = treeIndex;
774
        }
775

    
776
        //get taxonID for treeIndexes
777
        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(treeIndexSortIndexMap.keySet());
778

    
779
        //fill result list
780
        for (UUID originalTaxonUuid : originalTaxonUuids){
781
            GroupedTaxonDTO item = new GroupedTaxonDTO();
782
            result.add(item);
783
            item.setTaxonUuid(originalTaxonUuid);
784
            TreeIndex groupTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
785
            String groupIndexX = TreeIndex.toString(groupTreeIndex);
786
            while (groupTreeIndex != null){
787
                if (treeIndexTaxonIdMap.get(groupTreeIndex) != null){
788
                    UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
789
                    item.setGroupTaxonUuid(uuidAndLabel.getUuid());
790
                    item.setGroupTaxonName(uuidAndLabel.getTitleCache());
791
                    break;
792
                }else{
793
                    groupTreeIndex = groupTreeIndex.parent();
794
//                    int index = groupIndex.substring(0, groupIndex.length()-1).lastIndexOf(ITreeNode.separator);
795
//                    groupIndex = index < 0 ? null : groupIndex.substring(0, index+1);
796
                }
797
            }
798
        }
799

    
800
        return result;
801
    }
802

    
803
    @Override
804
    public List<GroupedTaxonDTO> groupTaxaByMarkedParents(List<UUID> originalTaxonUuids, UUID classificationUuid,
805
            MarkerType markerType, Boolean flag) {
806

    
807
        List<GroupedTaxonDTO> result = new ArrayList<>();
808

    
809
        //get treeindex for each taxonUUID
810
        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
811

    
812
        //get all marked tree indexes
813
        Set<TreeIndex> markedTreeIndexes = dao.getMarkedTreeIndexes(markerType, flag);
814

    
815

    
816
        Map<TreeIndex, TreeIndex> groupedMap = TreeIndex.group(markedTreeIndexes, taxonIdTreeIndexMap.values());
817
        Set<TreeIndex> notNullGroups = new HashSet<>(groupedMap.values());
818
        notNullGroups.remove(null);
819

    
820
        //get taxonInfo for treeIndexes
821
        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(notNullGroups);
822

    
823
        //fill result list
824
        for (UUID originalTaxonUuid : originalTaxonUuids){
825
            GroupedTaxonDTO item = new GroupedTaxonDTO();
826
            result.add(item);
827
            item.setTaxonUuid(originalTaxonUuid);
828

    
829
            TreeIndex toBeGroupedTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
830
            TreeIndex groupTreeIndex = groupedMap.get(toBeGroupedTreeIndex);
831
            UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
832
            if (uuidAndLabel != null){
833
                item.setGroupTaxonUuid(uuidAndLabel.getUuid());
834
                item.setGroupTaxonName(uuidAndLabel.getTitleCache());
835
            }
836
        }
837

    
838
        return result;
839
    }
840

    
841
    @Override
842
    public UUID getTaxonNodeUuidByTaxonUuid(UUID classificationUuid, UUID taxonUuid) {
843
        Map<UUID, UUID> map = dao.getTaxonNodeUuidByTaxonUuid(classificationUuid, Arrays.asList(taxonUuid));
844
        UUID taxonNodeUuid = map.get(taxonUuid);
845
        return taxonNodeUuid;
846
    }
847

    
848
    @Override
849
    public TaxonInContextDTO getTaxonInContext(UUID classificationUuid, UUID taxonBaseUuid,
850
            Boolean doChildren, Boolean doSynonyms, boolean includeUnpublished, List<UUID> ancestorMarkers,
851
            NodeSortMode sortMode) {
852
        TaxonInContextDTO result = new TaxonInContextDTO();
853

    
854
        TaxonBase<?> taxonBase = taxonDao.load(taxonBaseUuid);
855
        if (taxonBase == null){
856
            throw new EntityNotFoundException("Taxon with uuid " + taxonBaseUuid + " not found in datasource");
857
        }
858
        boolean isSynonym = false;
859
        Taxon acceptedTaxon;
860
        if (taxonBase.isInstanceOf(Synonym.class)){
861
            isSynonym = true;
862
            Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
863
            acceptedTaxon = synonym.getAcceptedTaxon();
864
            if (acceptedTaxon == null) {
865
                throw new EntityNotFoundException("Accepted taxon not found for synonym"  );
866
            }
867
            TaxonStatus taxonStatus = TaxonStatus.Synonym;
868
            if (synonym.getName()!= null && acceptedTaxon.getName() != null
869
                    && synonym.getName().getHomotypicalGroup().equals(acceptedTaxon.getName().getHomotypicalGroup())){
870
                taxonStatus = TaxonStatus.SynonymObjective;
871
            }
872
            result.setTaxonStatus(taxonStatus);
873

    
874
        }else{
875
            acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
876
            result.setTaxonStatus(TaxonStatus.Accepted);
877
        }
878
        UUID acceptedTaxonUuid = acceptedTaxon.getUuid();
879

    
880
        UUID taxonNodeUuid = getTaxonNodeUuidByTaxonUuid(classificationUuid, acceptedTaxonUuid);
881
        if (taxonNodeUuid == null) {
882
            throw new EntityNotFoundException("Taxon not found in classficiation with uuid " + classificationUuid + ". Either classification does not exist or does not contain taxon/synonym with uuid " + taxonBaseUuid );
883
        }
884
        result.setTaxonNodeUuid(taxonNodeUuid);
885

    
886
        //TODO make it a dao call
887
        Taxon parentTaxon = getParentTaxon(classificationUuid, acceptedTaxon);
888
        if (parentTaxon != null){
889
            result.setParentTaxonUuid(parentTaxon.getUuid());
890
            result.setParentTaxonLabel(parentTaxon.getTitleCache());
891
            if (parentTaxon.getName() != null){
892
                result.setParentNameLabel(parentTaxon.getName().getTitleCache());
893
            }
894
        }
895

    
896
        result.setTaxonUuid(taxonBaseUuid);
897
        result.setClassificationUuid(classificationUuid);
898
        if (taxonBase.getSec() != null){
899
            result.setSecundumUuid(taxonBase.getSec().getUuid());
900
            result.setSecundumLabel(taxonBase.getSec().getTitleCache());
901
        }
902
        result.setTaxonLabel(taxonBase.getTitleCache());
903

    
904
        TaxonName name = taxonBase.getName();
905
        result.setNameUuid(name.getUuid());
906
        result.setNameLabel(name.getTitleCache());
907
        result.setNameWithoutAuthor(name.getNameCache());
908
        result.setGenusOrUninomial(name.getGenusOrUninomial());
909
        result.setInfraGenericEpithet(name.getInfraGenericEpithet());
910
        result.setSpeciesEpithet(name.getSpecificEpithet());
911
        result.setInfraSpecificEpithet(name.getInfraSpecificEpithet());
912

    
913
        result.setAuthorship(name.getAuthorshipCache());
914

    
915
        Rank rank = name.getRank();
916
        if (rank != null){
917
            result.setRankUuid(rank.getUuid());
918
            String rankLabel = rank.getAbbreviation();
919
            if (StringUtils.isBlank(rankLabel)){
920
                rankLabel = rank.getLabel();
921
            }
922
            result.setRankLabel(rankLabel);
923
        }
924

    
925
        boolean recursive = false;
926
        Integer pageSize = null;
927
        Integer pageIndex = null;
928
        Pager<TaxonNodeDto> children = taxonNodeService.pageChildNodesDTOs(taxonNodeUuid, recursive, includeUnpublished, doSynonyms,
929
                sortMode, pageSize, pageIndex);
930

    
931
        //children
932
        if(! isSynonym) {
933
            for (TaxonNodeDto childDto : children.getRecords()){
934
                if (doChildren && childDto.getStatus().equals(TaxonStatus.Accepted)){
935
                    EntityDTO<Taxon> child = new EntityDTO<Taxon>(childDto.getTaxonUuid(), childDto.getTitleCache());
936
                    result.addChild(child);
937
                }else if (doSynonyms && childDto.getStatus().isSynonym()){
938
                    EntityDTO<Synonym> child = new EntityDTO<>(childDto.getTaxonUuid(), childDto.getTitleCache());
939
                    result.addSynonym(child);
940
                }
941
            }
942
        }else{
943
            result.setAcceptedTaxonUuid(acceptedTaxonUuid);
944
            String nameTitel = acceptedTaxon.getName() == null ? null : acceptedTaxon.getName().getTitleCache();
945
            result.setAcceptedTaxonLabel(acceptedTaxon.getTitleCache());
946
            result.setAcceptedNameLabel(nameTitel);
947
        }
948

    
949
        //marked ancestors
950
        if (ancestorMarkers != null && !ancestorMarkers.isEmpty()){
951
            @SuppressWarnings("rawtypes")
952
            List<DefinedTermBase> markerTypesTerms = termDao.list(ancestorMarkers, pageSize, null, null, null);
953
            List<MarkerType> markerTypes = new ArrayList<>();
954
            for (DefinedTermBase<?> term : markerTypesTerms){
955
                if (term.isInstanceOf(MarkerType.class)){
956
                    markerTypes.add(CdmBase.deproxy(term, MarkerType.class));
957
                }
958
            }
959
            if (! markerTypes.isEmpty()){
960
                TaxonNode node = taxonNodeDao.findByUuid(taxonNodeUuid);
961
                handleAncestorsForMarkersRecursive(result, markerTypes, node);
962
            }
963
        }
964

    
965
        return result;
966
    }
967

    
968
    private Taxon getParentTaxon(UUID classificationUuid, Taxon acceptedTaxon) {
969
        if (classificationUuid == null){
970
            return null;
971
        }
972
        TaxonNode parent = null;
973
        for (TaxonNode node : acceptedTaxon.getTaxonNodes()){
974
            if (classificationUuid.equals(node.getClassification().getUuid())){
975
                parent = node.getParent();
976
            }
977
        }
978
        if (parent != null){
979
            return parent.getTaxon();
980
        }
981
        return null;
982
    }
983

    
984
    private void handleAncestorsForMarkersRecursive(TaxonInContextDTO result, List<MarkerType> markerTypes, TaxonNode node) {
985
       for (MarkerType type : markerTypes){
986
            Taxon taxon = node.getTaxon();
987
            if (taxon != null && taxon.hasMarker(type, true)){
988
                String label =  taxon.getName() == null? taxon.getTitleCache() : taxon.getName().getTitleCache();
989
                MarkedEntityDTO<Taxon> dto = new MarkedEntityDTO<>(type, true, taxon.getUuid(), label);
990
                result.addMarkedAncestor(dto);
991
            }
992
        }
993
        TaxonNode parentNode = node.getParent();
994
        if (parentNode != null){
995
            handleAncestorsForMarkersRecursive(result, markerTypes, parentNode);
996
        }
997
    }
998

    
999
    @Override
1000
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1001
            Classification classification) {
1002
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, false);
1003
    }
1004

    
1005
    @Override
1006
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1007
            UUID classificationUuid) {
1008
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classificationUuid, false);
1009
    }
1010

    
1011
    @Override
1012
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1013
            UUID classificationUuid, Integer limit, String pattern) {
1014
        return  getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classificationUuid,  limit, pattern, false);
1015
    }
1016

    
1017
    @Override
1018
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1019
            Classification classification, Integer limit, String pattern) {
1020
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, limit, pattern, false);
1021
    }
1022
}
(7-7/107)