Project

General

Profile

Download (44.7 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
import java.util.stream.Collectors;
25

    
26
import javax.persistence.EntityNotFoundException;
27

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

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

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

    
93
    private static final Logger logger = Logger.getLogger(ClassificationServiceImpl.class);
94

    
95
    @Autowired
96
    private ITaxonNodeDao taxonNodeDao;
97

    
98
    @Autowired
99
    private ITaxonDao taxonDao;
100

    
101
    @Autowired
102
    private ITaxonNodeService taxonNodeService;
103

    
104
    @Autowired
105
    private IDefinedTermDao termDao;
106

    
107
    @Autowired
108
    private IBeanInitializer defaultBeanInitializer;
109

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

    
116
    private Comparator<TaxonNode> taxonNodeComparator;
117

    
118
    @Autowired
119
    public void setTaxonNodeComparator(ITaxonNodeComparator<TaxonNode> taxonNodeComparator){
120
        this.taxonNodeComparator = (Comparator<TaxonNode>) taxonNodeComparator;
121
    }
122

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

    
128
        return loadTaxonNode(node.getUuid(), propertyPaths);
129
    }
130

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

    
135
    @Override
136
    public List<TaxonNode> listRankSpecificRootNodes(Classification classification,
137
            TaxonNode subtree, Rank rank,
138
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
139
        return pageRankSpecificRootNodes(classification, subtree, rank, includeUnpublished, pageSize, pageIndex, propertyPaths).getRecords();
140
    }
141

    
142
    @Override
143
    public List<TaxonNodeDto> listRankSpecificRootNodeDtos(Classification classification, TaxonNode subtree,
144
            Rank rank, boolean includeUnpublished, Integer pageSize, Integer pageIndex, TaxonNodeDtoSortMode sortMode,
145
            List<String> propertyPaths) {
146
        List<TaxonNode> list = listRankSpecificRootNodes(classification, subtree, rank, includeUnpublished, pageSize, pageIndex, propertyPaths);
147
        return list.stream().filter(e ->  e != null).map(e -> new TaxonNodeDto(e)).sorted(sortMode.comparator()).collect(Collectors.toList());
148
    }
149

    
150
    @Override
151
    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, Rank rank,
152
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
153
        return pageRankSpecificRootNodes(classification, null, rank, includeUnpublished, pageSize, pageIndex, propertyPaths);
154
    }
155

    
156
    @Override
157
    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, TaxonNode subtree, Rank rank,
158
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
159
        long[] numberOfResults = dao.countRankSpecificRootNodes(classification, subtree, includeUnpublished, rank);
160
        long totalNumberOfResults = numberOfResults[0] + (numberOfResults.length > 1 ? numberOfResults[1] : 0);
161

    
162
        List<TaxonNode> results = new ArrayList<>();
163

    
164
        if (AbstractPagerImpl.hasResultsInRange(totalNumberOfResults, pageIndex, pageSize)) { // no point checking again
165
            Integer limit = PagerUtils.limitFor(pageSize);
166
            Integer start = PagerUtils.startFor(pageSize, pageIndex);
167

    
168
            Integer remainingLimit = limit;
169
            int[] queryIndexes = rank == null ? new int[]{0} : new int[]{0,1};
170

    
171
            for(int queryIndex: queryIndexes) {
172
                if(start != null && start > numberOfResults[queryIndex]) {
173
                    // start in next query with new start value
174
                    start = start - (int)numberOfResults[queryIndex];
175
                    continue;
176
                }
177

    
178
                List<TaxonNode> perQueryResults = dao.listRankSpecificRootNodes(classification,
179
                        subtree, rank, includeUnpublished, remainingLimit,
180
                        start, propertyPaths, queryIndex);
181
                results.addAll(perQueryResults);
182
                if(remainingLimit != null ){
183
                    remainingLimit = remainingLimit - results.size();
184
                    if(remainingLimit <= 0) {
185
                        // no need to run further queries if first query returned enough items!
186
                        break;
187
                    }
188
                    // start at with fist item of next query to fetch the remaining items
189
                    start = 0;
190
                }
191
            }
192
        }
193
//        long start_t = System.currentTimeMillis();
194
        Collections.sort(results, taxonNodeComparator); // TODO is ordering during the hibernate query in the dao possible?
195
//        System.err.println("service.pageRankSpecificRootNodes() - Collections.sort(results,  taxonNodeComparator) " + (System.currentTimeMillis() - start_t));
196
        return new DefaultPagerImpl<>(pageIndex, totalNumberOfResults, pageSize, results);
197

    
198
    }
199

    
200
    @Override
201
    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, Rank baseRank,
202
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
203
        return loadTreeBranch(taxonNode, null, baseRank, includeUnpublished, propertyPaths);
204
    }
205

    
206
    @Override
207
    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, TaxonNode subtree, Rank baseRank,
208
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
209

    
210
        TaxonNode thisNode = taxonNodeDao.load(taxonNode.getUuid(), propertyPaths);
211
        if(baseRank != null){
212
            baseRank = (Rank) termDao.load(baseRank.getUuid());
213
        }
214
        if (!includeUnpublished && thisNode.getTaxon() != null && !thisNode.getTaxon().isPublish()){
215
            throw new UnpublishedException("Final taxon in tree branch is unpublished.");
216
        }
217

    
218
        List<TaxonNode> pathToRoot = new ArrayList<>();
219
        pathToRoot.add(thisNode);
220

    
221
        while(!thisNode.isTopmostNode()){
222
            //TODO why do we need to deproxy here?
223
            //     without this thisNode.getParent() will return NULL in
224
            //     some cases (environment dependend?) even if the parent exits
225
            TaxonNode parentNode = CdmBase.deproxy(thisNode).getParent();
226

    
227
            if(parentNode == null){
228
                throw new NullPointerException("Taxon node " + thisNode + " must have a parent since it is not top most");
229
            }
230
            if(parentNode.getTaxon() == null){
231
                throw new NullPointerException("The taxon associated with taxon node " + parentNode + " is NULL");
232
            }
233
            if(!includeUnpublished && !parentNode.getTaxon().isPublish()){
234
                throw new UnpublishedException("Some taxon in tree branch is unpublished.");
235
            }
236
            if(parentNode.getTaxon().getName() == null){
237
                throw new NullPointerException("The name of the taxon associated with taxonNode " + parentNode + " is NULL");
238
            }
239

    
240
            Rank parentNodeRank = (parentNode.getTaxon().getName() == null) ? null : parentNode.getTaxon().getName().getRank();
241
            // stop if the next parent is higher than the baseRank
242
            if(baseRank != null && parentNodeRank != null && baseRank.isLower(parentNodeRank)){
243
                break;
244
            }
245
            if((subtree!= null && !subtree.isAncestor(parentNode) )){
246
                break;
247
            }
248

    
249
            pathToRoot.add(parentNode);
250
            thisNode = parentNode;
251
        }
252

    
253
        // initialize and invert order of nodes in list
254
        defaultBeanInitializer.initializeAll(pathToRoot, propertyPaths);
255
        Collections.reverse(pathToRoot);
256

    
257
        return pathToRoot;
258
    }
259

    
260
    @Override
261
    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification, Rank baseRank,
262
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
263
        return loadTreeBranchToTaxon(taxon, classification, null, baseRank, includeUnpublished, propertyPaths);
264
    }
265

    
266
    @Override
267
    public List<TaxonNodeDto> loadTreeBranchDTOsToTaxon(Taxon taxon, Classification classification,
268
            TaxonNode subtree, Rank baseRank,
269
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException {
270
        List<TaxonNode> list = loadTreeBranchToTaxon(taxon, classification, subtree, baseRank, includeUnpublished, propertyPaths);
271
        return list.stream().map(e -> new TaxonNodeDto(e)).collect(Collectors.toList());
272
    }
273

    
274
    @Override
275
    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification,
276
            TaxonNode subtree, Rank baseRank,
277
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
278

    
279
        UUID nodeUuid = getTaxonNodeUuidByTaxonUuid(classification.getUuid(), taxon.getUuid());
280
        TaxonNode node = taxonNodeService.find(nodeUuid);
281
        if(node == null){
282
            logger.warn("The specified taxon is not found in the given tree.");
283
            return new ArrayList<>(0);
284
        }else if (subtree != null && !node.isDescendant(subtree)){
285
            //TODO handle as exception? E.g. FilterException, AccessDeniedException?
286
            logger.warn("The specified taxon is not found for the given subtree.");
287
            return new ArrayList<>(0);
288
        }
289

    
290
        return loadTreeBranch(node, subtree, baseRank, includeUnpublished, propertyPaths);
291
    }
292

    
293

    
294
    @Override
295
    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
296
            List<String> propertyPaths) {
297
        taxonNode = taxonNodeDao.load(taxonNode.getUuid());
298
        List<TaxonNode> childNodes = new ArrayList<TaxonNode>(taxonNode.getChildNodes());
299
        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
300
        Collections.sort(childNodes, taxonNodeComparator);
301
        return childNodes;
302
    }
303

    
304
    @Override
305
    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid,
306
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths){
307
        try {
308
            return listChildNodesOfTaxon(taxonUuid, classificationUuid, null, includeUnpublished, pageSize, pageIndex, propertyPaths);
309
        } catch (FilterException e) {
310
            throw new RuntimeException(e);  //this should not happen as filter is null
311
        }
312
    }
313

    
314
    @Override
315
    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid, UUID subtreeUuid,
316
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) throws FilterException{
317

    
318
        Classification classification = dao.load(classificationUuid);
319
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
320
        TaxonNode subtree = taxonNodeDao.load(subtreeUuid);
321
        if (subtreeUuid != null && subtree == null){
322
            throw new FilterException("Taxon node for subtree filter can not be found in database", true);
323
        }
324

    
325
        List<TaxonNode> results = dao.listChildrenOf(
326
                taxon, classification, subtree, includeUnpublished, pageSize, pageIndex, propertyPaths);
327
        Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
328
        return results;
329
    }
330

    
331
    @Override
332
    public List<TaxonNodeDto> listChildNodeDtosOfTaxon(UUID taxonUuid, UUID classificationUuid, UUID subtreeUuid, boolean includeUnpublished,
333
            Integer pageSize, Integer pageIndex, TaxonNodeDtoSortMode sortMode, List<String> propertyPaths) throws FilterException{
334
        Classification classification = dao.load(classificationUuid);
335
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
336
        TaxonNode subtree = taxonNodeDao.load(subtreeUuid);
337
        if (subtreeUuid != null && subtree == null){
338
            throw new FilterException("Taxon node for subtree filter can not be found in database", true);
339
        }
340

    
341
        List<TaxonNode> results = dao.listChildrenOf(
342
                taxon, classification, subtree, includeUnpublished, pageSize, pageIndex, propertyPaths);
343
        Comparator<TaxonNodeDto> comparator = sortMode.comparator();
344
        // TODO order during the hibernate query in the dao?
345
        List<TaxonNodeDto> dtos = results.stream().map(e -> new TaxonNodeDto(e)).sorted(comparator).collect(Collectors.toList());
346
        return dtos;
347
    }
348

    
349
    @Override
350
    public Pager<TaxonNode> pageSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, boolean includeUnpublished,
351
            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
352

    
353
        Classification classification = dao.load(classificationUuid);
354
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
355

    
356
        long numberOfResults = dao.countSiblingsOf(taxon, classification, includeUnpublished);
357

    
358
        List<TaxonNode> results;
359
        if(PagerUtils.hasResultsInRange(numberOfResults, pageIndex, pageSize)) {
360
            results = dao.listSiblingsOf(taxon, classification, includeUnpublished, pageSize, pageIndex, propertyPaths);
361
            Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
362
        } else {
363
            results = new ArrayList<>();
364
        }
365

    
366
        return new DefaultPagerImpl<>(pageIndex, numberOfResults, pageSize, results);
367
    }
368

    
369
    @Override
370
    public List<TaxonNode> listSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, boolean includeUnpublished,
371
            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
372

    
373
        Pager<TaxonNode> pager = pageSiblingsOfTaxon(taxonUuid, classificationUuid, includeUnpublished, pageSize, pageIndex, propertyPaths);
374
        return pager.getRecords();
375
    }
376

    
377
    @Override
378
    public ITaxonTreeNode getTreeNodeByUuid(UUID uuid){
379
        ITaxonTreeNode treeNode = taxonNodeDao.findByUuid(uuid);
380
        if(treeNode == null){
381
            treeNode = dao.findByUuid(uuid);
382
        }
383

    
384
        return treeNode;
385
    }
386

    
387
    @Override
388
    public TaxonNode getRootNode(UUID classificationUuid){
389
        return dao.getRootNode(classificationUuid);
390
    }
391

    
392
    @Override
393
    public List<Classification> listClassifications(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
394
        return dao.list(limit, start, orderHints, propertyPaths);
395
    }
396

    
397
    @Override
398
    public UUID removeTreeNode(ITaxonTreeNode treeNode) {
399
        if(treeNode instanceof Classification){
400
            return dao.delete((Classification) treeNode);
401
        }else if(treeNode instanceof TaxonNode){
402
            return taxonNodeDao.delete((TaxonNode)treeNode);
403
        }
404
        return null;
405
    }
406

    
407
    @Override
408
    public Map<UUID, TaxonNode> saveTaxonNodeAll(
409
            Collection<TaxonNode> taxonNodeCollection) {
410
        return taxonNodeDao.saveAll(taxonNodeCollection);
411
    }
412

    
413
    @Override
414
    public UUID saveClassification(Classification classification) {
415

    
416
       taxonNodeDao.saveOrUpdateAll(classification.getAllNodes());
417
       UUID result =dao.saveOrUpdate(classification);
418
       return result;
419
    }
420

    
421
    @Override
422
    public UUID saveTreeNode(ITaxonTreeNode treeNode) {
423
        if(treeNode instanceof Classification){
424
            return dao.save((Classification) treeNode).getUuid();
425
        }else if(treeNode instanceof TaxonNode){
426
            return taxonNodeDao.save((TaxonNode)treeNode).getUuid();
427
        }
428
        return null;
429
    }
430

    
431
    @Override
432
    public List<TaxonNode> getAllNodes(){
433
        return taxonNodeDao.list(null,null);
434
    }
435

    
436
    @Override
437
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, Integer limit, String pattern, boolean searchForClassifications, boolean includeDoubtful) {
438
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid),  limit, pattern, searchForClassifications, includeDoubtful);
439
    }
440

    
441
    @Override
442
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification,  Integer limit, String pattern, boolean searchForClassifications) {
443
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification,  limit, pattern, searchForClassifications);
444
    }
445

    
446
    @Override
447
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, boolean searchForClassifications ) {
448
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid), null, null, searchForClassifications);
449
    }
450

    
451
    @Override
452
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, boolean searchForClassifications ) {
453
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, null, null, searchForClassifications);
454
    }
455

    
456
    @Override
457
    public List<UuidAndTitleCache<Classification>> getUuidAndTitleCache(Integer limit, String pattern) {
458
        return dao.getUuidAndTitleCache(limit, pattern);
459
    }
460

    
461
    @Override
462
    public Map<UUID, List<MediaRepresentation>> getAllMediaForChildNodes(
463
            TaxonNode taxonNode, List<String> propertyPaths, int size,
464
            int height, int widthOrDuration, String[] mimeTypes) {
465

    
466
        TreeMap<UUID, List<MediaRepresentation>> result = new TreeMap<>();
467
        List<MediaRepresentation> mediaRepresentations = new ArrayList<>();
468

    
469
        //add all media of the children to the result map
470
        if (taxonNode != null){
471

    
472
            List<TaxonNode> nodes = new ArrayList<>();
473

    
474
            nodes.add(loadTaxonNode(taxonNode.getUuid(), propertyPaths));
475
            nodes.addAll(loadChildNodesOfTaxonNode(taxonNode, propertyPaths));
476

    
477
            for(TaxonNode node : nodes){
478
                Taxon taxon = node.getTaxon();
479
                for (TaxonDescription taxonDescription: taxon.getDescriptions()){
480
                    for (DescriptionElementBase descriptionElement: taxonDescription.getElements()){
481
                        for(Media media : descriptionElement.getMedia()){
482
                            //find the best matching representation
483
                            mediaRepresentations.add(MediaUtils.findBestMatchingRepresentation(media,null, size, height, widthOrDuration, mimeTypes, MediaUtils.MissingValueStrategy.MAX));
484
                        }
485
                    }
486
                }
487
                result.put(taxon.getUuid(), mediaRepresentations);
488
            }
489
        }
490

    
491
        return result;
492
    }
493

    
494
    @Override
495
    @Transactional(readOnly = false)
496
    public UpdateResult updateCaches(Class<? extends Classification> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<Classification> cacheStrategy, IProgressMonitor monitor) {
497
        if (clazz == null){
498
            clazz = Classification.class;
499
        }
500
        return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
501
    }
502

    
503
    /**
504
     *
505
     * @param allNodesOfClassification
506
     * @return null - if  allNodesOfClassification is empty <br>
507
     */
508

    
509
    private Map<String, List<TaxonNode>> getSortedGenusList(Collection<TaxonNode> allNodesOfClassification){
510

    
511
    	if(allNodesOfClassification == null || allNodesOfClassification.isEmpty()){
512
    		return null;
513
    	}
514
    	Map<String, List<TaxonNode>> sortedGenusMap = new HashMap<>();
515
    	for(TaxonNode node:allNodesOfClassification){
516
    		Taxon taxon = node.getTaxon();
517
    		INonViralName name = taxon.getName();
518
    		String genusOrUninomial = name.getGenusOrUninomial();
519
    		//if rank unknown split string and take first word
520
    		if(genusOrUninomial == null){
521
    			String titleCache = taxon.getTitleCache();
522
    			String[] split = titleCache.split("\\s+");
523
    			for(String s:split){
524
    				genusOrUninomial = s;
525
    				break;
526
    			}
527
    		}
528
    		//if node has children
529

    
530
    		//retrieve list from map if not create List
531
    		if(sortedGenusMap.containsKey(genusOrUninomial)){
532
    			List<TaxonNode> list = sortedGenusMap.get(genusOrUninomial);
533
    			list.add(node);
534
    			sortedGenusMap.put(genusOrUninomial, list);
535
    		}else{
536
    			//create List for genus
537
    			List<TaxonNode> list = new ArrayList<>();
538
    			list.add(node);
539
    			sortedGenusMap.put(genusOrUninomial, list);
540
    		}
541
    	}
542
    	return sortedGenusMap;
543
    }
544

    
545
    /**
546
     *
547
     * creates new Classification and parent TaxonNodes at genus level
548
     *
549
     *
550
     * @param map GenusMap which holds a name (Genus) and all the same Taxa as a list
551
     * @param classification you want to improve the hierarchy (will not be modified)
552
     * @param configurator to change certain settings, if null then standard settings will be taken
553
     * @return new classification with parentNodes for each entry in the map
554
     */
555
    @SuppressWarnings({ "unchecked" })
556
	@Transactional(readOnly = false)
557
	@Override
558
    public UpdateResult createHierarchyInClassification(Classification classification, CreateHierarchyForClassificationConfigurator configurator){
559

    
560
        UpdateResult result = new UpdateResult();
561
        Set<TaxonNode> taxonNodesToSave = new HashSet<>();
562

    
563
    	classification = dao.findByUuid(classification.getUuid());
564
    	Map<String, List<TaxonNode>> map = getSortedGenusList(classification.getAllNodes());
565

    
566
    	final String APPENDIX = "repaired";
567
    	String titleCache = StringUtils.isBlank(classification.getTitleCache()) ? " " : classification.getTitleCache() ;
568
    	//TODO classification clone???
569
    	Classification newClassification = Classification.NewInstance(titleCache +" "+ APPENDIX);
570
    	newClassification.setReference(classification.getReference());
571

    
572
    	for(Map.Entry<String, List<TaxonNode>> entry:map.entrySet()){
573
    		String genus = entry.getKey();
574
    		List<TaxonNode> listOfTaxonNodes = entry.getValue();
575
    		TaxonNode parentNode = null;
576
    		//Search for genus in list
577
    		for(TaxonNode tNode:listOfTaxonNodes){
578
    			//take that taxonNode as parent and remove from list with all it possible children
579
    			//FIXME NPE for name
580
    			TaxonName name = tNode.getTaxon().getName();
581
    			if(name.getNameCache().equalsIgnoreCase(genus)){
582
    				TaxonNode clone = tNode.clone();
583
    				if(!tNode.hasChildNodes()){
584
    					//FIXME remove classification
585
//    					parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference());
586
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
587
    					//remove taxonNode from list because just added to classification
588
    					result.addUpdatedObject(tNode);
589
    					listOfTaxonNodes.remove(tNode);
590
    				}else{
591
    					//get all childNodes
592
    					//save prior Hierarchy and remove them from the list
593
    					List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tNode, clone, result);
594
//    					//FIXME remove classification
595
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
596
    					//remove taxonNode from list because just added to classification
597
    					result.addUpdatedObject(tNode);
598
    					listOfTaxonNodes.remove(tNode);
599
    					if(copyAllChildrenToTaxonNode != null){
600
    						listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
601
    					}
602
    				}
603
    				break;
604
    			}
605
    		}
606
    		if(parentNode == null){
607
    			//if no match found in list, create parentNode
608
    			NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
609
    			TaxonName TaxonName = (TaxonName)parser.parseFullName(genus);
610
    			//TODO Sec via configurator
611
    			Taxon taxon = Taxon.NewInstance(TaxonName, null);
612
    			parentNode = newClassification.addChildTaxon(taxon, 0, null, null);
613
    			result.addUpdatedObject(parentNode);
614
    		}
615
    		taxonNodesToSave.add(parentNode);
616

    
617
    		//iterate over the remaining list
618
    		for(TaxonNode tn : listOfTaxonNodes){
619
    			//if TaxonNode has a parent and this is not the classification then skip it
620
    			//and add to new classification via the parentNode as children of it
621
    			//this should assures to keep the already existing hierarchy
622
    			//FIXME: Assert is not rootnode --> entrypoint is not classification in future but rather rootNode
623

    
624
    			if(!tn.isTopmostNode()){
625
    				continue; //skip to next taxonNode
626
    			}
627

    
628
    			TaxonNode clone = tn.clone();
629
    			//FIXME: citation from node
630
    			//TODO: addChildNode without citation and references
631
    			TaxonNode taxonNode = parentNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
632
    			taxonNodesToSave.add(taxonNode);
633

    
634
    			result.addUnChangedObject(clone);
635
    			if(tn.hasChildNodes()){
636
    				//save hierarchy in new classification
637
    				List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tn, taxonNode, result);
638
    				if(copyAllChildrenToTaxonNode != null){
639
    					listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
640
    				}
641
    			}
642
    		}
643
    	}
644
    	dao.saveOrUpdate(newClassification);
645
    	taxonNodeDao.saveOrUpdateAll(taxonNodesToSave);
646
    	result.setCdmEntity(newClassification);
647
    	return result;
648
    }
649

    
650
    /**
651
     *
652
     * recursive method to get all childnodes of taxonNode in classification.
653
     *
654
     * @param classification just for References and Citation, can be null
655
     * @param copyFromNode TaxonNode with Children
656
     * @param copyToNode TaxonNode which will receive the children
657
     * @return List of ChildNode which has been added. If node has no children returns null
658
     */
659
   private List<TaxonNode> copyAllChildrenToTaxonNode(TaxonNode copyFromNode, TaxonNode copyToNode, UpdateResult result) {
660
		List<TaxonNode> childNodes;
661
		if(!copyFromNode.hasChildNodes()){
662
			return null;
663
		}else{
664
			childNodes = copyFromNode.getChildNodes();
665
		}
666
		for(TaxonNode childNode:childNodes){
667
			TaxonNode clone = childNode.clone();
668
			result.addUnChangedObject(clone);
669
			if(childNode.hasChildNodes()){
670
				copyAllChildrenToTaxonNode(childNode, clone, result);
671
			}
672
			//FIXME: citation from node instead of classification
673
//			copyToNode.addChildNode(clone,classification.getCitation(), classification.getMicroReference());
674
			copyToNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
675
		}
676
		return childNodes;
677
	}
678

    
679
    @Override
680
    public ClassificationLookupDTO classificationLookup(Classification classification) {
681
        return dao.classificationLookup(classification);
682
    }
683

    
684
    @Override
685
    @Transactional
686
    public DeleteResult delete(UUID classificationUuid, TaxonDeletionConfigurator config){
687
        DeleteResult result = new DeleteResult();
688
        Classification classification = dao.findByUuid(classificationUuid);
689
        if (classification == null){
690
            result.addException(new IllegalArgumentException("The classification does not exist in database."));
691
            result.setAbort();
692
            return result;
693
        }
694
        if (!classification.hasChildNodes()){
695
            dao.delete(classification);
696
            result.addDeletedObject(classification);
697
            return result;
698
        }
699
        if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)){
700
//            TaxonNode root = classification.getRootNode();
701
//            result.includeResult(taxonNodeService.deleteTaxonNode(HibernateProxyHelper.deproxy(root), config));
702
//            result.addDeletedObject(classification);
703
            dao.delete(classification);
704
            result.addDeletedObject(classification);
705
            return result;
706
        }
707

    
708

    
709
        return result;
710
    }
711

    
712
    @Override
713
    public List<GroupedTaxonDTO> groupTaxaByHigherTaxon(List<UUID> originalTaxonUuids, UUID classificationUuid, Rank minRank, Rank maxRank){
714
        List<GroupedTaxonDTO> result = new ArrayList<>();
715

    
716
        //get treeindex for each taxonUUID
717
        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
718

    
719
        //build treeindex list (or tree)
720
        //TODO make it work with TreeIndex or move there
721
        List<String> treeIndexClosureStr = new ArrayList<>();
722
        for (TreeIndex treeIndex : taxonIdTreeIndexMap.values()){
723
            String[] splits = treeIndex.toString().substring(1).split(ITreeNode.separator);
724
            String currentIndex = ITreeNode.separator;
725
            for (String split : splits){
726
                if (split.equals("")){
727
                    continue;
728
                }
729
                currentIndex += split + ITreeNode.separator;
730
                if (!treeIndexClosureStr.contains(currentIndex) && !split.startsWith(ITreeNode.treePrefix)){
731
                    treeIndexClosureStr.add(currentIndex);
732
                }
733
            }
734
        }
735

    
736
        //get rank sortindex for all parent taxa with sortindex <= minRank and sortIndex >= maxRank (if available)
737
        Integer minRankOrderIndex = minRank == null ? null : minRank.getOrderIndex();
738
        Integer maxRankOrderIndex = maxRank == null ? null : maxRank.getOrderIndex();
739
        List<TreeIndex> treeIndexClosure = TreeIndex.NewListInstance(treeIndexClosureStr);
740

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

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

    
746
        Map<TreeIndex, Integer> treeIndexSortIndexMap = new HashMap<>();
747
        TreeIndex lastTreeIndex = null;
748
        for (TreeIndex treeIndex : treeIndexList){
749
            if (lastTreeIndex != null && lastTreeIndex.hasChild(treeIndex)){
750
                treeIndexSortIndexMap.remove(lastTreeIndex);
751
            }
752
            treeIndexSortIndexMap.put(treeIndex, treeIndexSortIndexMapTmp.get(treeIndex));
753
            lastTreeIndex = treeIndex;
754
        }
755

    
756
        //get taxonID for treeIndexes
757
        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(treeIndexSortIndexMap.keySet());
758

    
759
        //fill result list
760
        for (UUID originalTaxonUuid : originalTaxonUuids){
761
            GroupedTaxonDTO item = new GroupedTaxonDTO();
762
            result.add(item);
763
            item.setTaxonUuid(originalTaxonUuid);
764
            TreeIndex groupTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
765
            String groupIndexX = TreeIndex.toString(groupTreeIndex);
766
            while (groupTreeIndex != null){
767
                if (treeIndexTaxonIdMap.get(groupTreeIndex) != null){
768
                    UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
769
                    item.setGroupTaxonUuid(uuidAndLabel.getUuid());
770
                    item.setGroupTaxonName(uuidAndLabel.getTitleCache());
771
                    break;
772
                }else{
773
                    groupTreeIndex = groupTreeIndex.parent();
774
//                    int index = groupIndex.substring(0, groupIndex.length()-1).lastIndexOf(ITreeNode.separator);
775
//                    groupIndex = index < 0 ? null : groupIndex.substring(0, index+1);
776
                }
777
            }
778
        }
779

    
780
        return result;
781
    }
782

    
783
    @Override
784
    public List<GroupedTaxonDTO> groupTaxaByMarkedParents(List<UUID> originalTaxonUuids, UUID classificationUuid,
785
            MarkerType markerType, Boolean flag) {
786

    
787
        List<GroupedTaxonDTO> result = new ArrayList<>();
788

    
789
        //get treeindex for each taxonUUID
790
        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
791

    
792
        //get all marked tree indexes
793
        Set<TreeIndex> markedTreeIndexes = dao.getMarkedTreeIndexes(markerType, flag);
794

    
795
        Map<TreeIndex, TreeIndex> groupedMap = TreeIndex.group(markedTreeIndexes, taxonIdTreeIndexMap.values());
796
        Set<TreeIndex> notNullGroups = new HashSet<>(groupedMap.values());
797
        notNullGroups.remove(null);
798

    
799
        //get taxonInfo for treeIndexes
800
        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(notNullGroups);
801

    
802
        //fill result list
803
        for (UUID originalTaxonUuid : originalTaxonUuids){
804
            GroupedTaxonDTO item = new GroupedTaxonDTO();
805
            result.add(item);
806
            item.setTaxonUuid(originalTaxonUuid);
807

    
808
            TreeIndex toBeGroupedTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
809
            TreeIndex groupTreeIndex = groupedMap.get(toBeGroupedTreeIndex);
810
            UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
811
            if (uuidAndLabel != null){
812
                item.setGroupTaxonUuid(uuidAndLabel.getUuid());
813
                item.setGroupTaxonName(uuidAndLabel.getTitleCache());
814
            }
815
        }
816

    
817
        return result;
818
    }
819

    
820
    @Override
821
    public UUID getTaxonNodeUuidByTaxonUuid(UUID classificationUuid, UUID taxonUuid) {
822
        Map<UUID, UUID> map = dao.getTaxonNodeUuidByTaxonUuid(classificationUuid, Arrays.asList(taxonUuid));
823
        UUID taxonNodeUuid = map.get(taxonUuid);
824
        return taxonNodeUuid;
825
    }
826

    
827
    @Override
828
    public TaxonInContextDTO getTaxonInContext(UUID classificationUuid, UUID taxonBaseUuid,
829
            Boolean doChildren, Boolean doSynonyms, boolean includeUnpublished, List<UUID> ancestorMarkers,
830
            TaxonNodeSortMode sortMode) {
831

    
832
        TaxonInContextDTO result = new TaxonInContextDTO();
833

    
834
        TaxonBase<?> taxonBase = taxonDao.load(taxonBaseUuid);
835
        if (taxonBase == null){
836
            throw new EntityNotFoundException("Taxon with uuid " + taxonBaseUuid + " not found in datasource");
837
        }
838
        boolean isSynonym = false;
839
        Taxon acceptedTaxon;
840
        if (taxonBase.isInstanceOf(Synonym.class)){
841
            isSynonym = true;
842
            Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
843
            acceptedTaxon = synonym.getAcceptedTaxon();
844
            if (acceptedTaxon == null) {
845
                throw new EntityNotFoundException("Accepted taxon not found for synonym"  );
846
            }
847
            TaxonStatus taxonStatus = TaxonStatus.Synonym;
848
            if (synonym.getName()!= null && acceptedTaxon.getName() != null
849
                    && synonym.getName().getHomotypicalGroup().equals(acceptedTaxon.getName().getHomotypicalGroup())){
850
                taxonStatus = TaxonStatus.SynonymObjective;
851
            }
852
            result.setTaxonStatus(taxonStatus);
853

    
854
        }else{
855
            acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
856
            result.setTaxonStatus(TaxonStatus.Accepted);
857
        }
858
        UUID acceptedTaxonUuid = acceptedTaxon.getUuid();
859

    
860
        UUID taxonNodeUuid = getTaxonNodeUuidByTaxonUuid(classificationUuid, acceptedTaxonUuid);
861
        if (taxonNodeUuid == null) {
862
            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 );
863
        }
864
        result.setTaxonNodeUuid(taxonNodeUuid);
865

    
866
        //TODO make it a dao call
867
        Taxon parentTaxon = getParentTaxon(classificationUuid, acceptedTaxon);
868
        if (parentTaxon != null){
869
            result.setParentTaxonUuid(parentTaxon.getUuid());
870
            result.setParentTaxonLabel(parentTaxon.getTitleCache());
871
            if (parentTaxon.getName() != null){
872
                result.setParentNameLabel(parentTaxon.getName().getTitleCache());
873
            }
874
        }
875

    
876
        result.setTaxonUuid(taxonBaseUuid);
877
        result.setClassificationUuid(classificationUuid);
878
        if (taxonBase.getSec() != null){
879
            result.setSecundumUuid(taxonBase.getSec().getUuid());
880
            result.setSecundumLabel(taxonBase.getSec().getTitleCache());
881
        }
882
        result.setTaxonLabel(taxonBase.getTitleCache());
883

    
884
        TaxonName name = taxonBase.getName();
885
        result.setNameUuid(name.getUuid());
886
        result.setNameLabel(name.getTitleCache());
887
        result.setNameWithoutAuthor(name.getNameCache());
888
        result.setGenusOrUninomial(name.getGenusOrUninomial());
889
        result.setInfraGenericEpithet(name.getInfraGenericEpithet());
890
        result.setSpeciesEpithet(name.getSpecificEpithet());
891
        result.setInfraSpecificEpithet(name.getInfraSpecificEpithet());
892

    
893
        result.setAuthorship(name.getAuthorshipCache());
894

    
895
        Rank rank = name.getRank();
896
        if (rank != null){
897
            result.setRankUuid(rank.getUuid());
898
            String rankLabel = rank.getAbbreviation();
899
            if (StringUtils.isBlank(rankLabel)){
900
                rankLabel = rank.getLabel();
901
            }
902
            result.setRankLabel(rankLabel);
903
        }
904

    
905
        boolean recursive = false;
906
        Integer pageSize = null;
907
        Integer pageIndex = null;
908
        Pager<TaxonNodeDto> children = taxonNodeService.pageChildNodesDTOs(taxonNodeUuid, recursive, includeUnpublished, doSynonyms,
909
                sortMode, pageSize, pageIndex);
910

    
911
        //children
912
        if(! isSynonym) {
913
            for (TaxonNodeDto childDto : children.getRecords()){
914
                if (doChildren && childDto.getTaxonStatus().equals(TaxonStatus.Accepted)){
915
                    EntityDTO<Taxon> child = new EntityDTO<Taxon>(childDto.getTaxonUuid(), childDto.getTitleCache());
916
                    result.addChild(child);
917
                }else if (doSynonyms && childDto.getTaxonStatus().isSynonym()){
918
                    EntityDTO<Synonym> child = new EntityDTO<>(childDto.getTaxonUuid(), childDto.getTitleCache());
919
                    result.addSynonym(child);
920
                }
921
            }
922
        }else{
923
            result.setAcceptedTaxonUuid(acceptedTaxonUuid);
924
            String nameTitel = acceptedTaxon.getName() == null ? null : acceptedTaxon.getName().getTitleCache();
925
            result.setAcceptedTaxonLabel(acceptedTaxon.getTitleCache());
926
            result.setAcceptedNameLabel(nameTitel);
927
        }
928

    
929
        //marked ancestors
930
        if (ancestorMarkers != null && !ancestorMarkers.isEmpty()){
931
            @SuppressWarnings("rawtypes")
932
            List<DefinedTermBase> markerTypesTerms = termDao.list(ancestorMarkers, pageSize, null, null, null);
933
            List<MarkerType> markerTypes = new ArrayList<>();
934
            for (DefinedTermBase<?> term : markerTypesTerms){
935
                if (term.isInstanceOf(MarkerType.class)){
936
                    markerTypes.add(CdmBase.deproxy(term, MarkerType.class));
937
                }
938
            }
939
            if (! markerTypes.isEmpty()){
940
                TaxonNode node = taxonNodeDao.findByUuid(taxonNodeUuid);
941
                handleAncestorsForMarkersRecursive(result, markerTypes, node);
942
            }
943
        }
944

    
945
        return result;
946
    }
947

    
948
    private Taxon getParentTaxon(UUID classificationUuid, Taxon acceptedTaxon) {
949
        if (classificationUuid == null){
950
            return null;
951
        }
952
        TaxonNode parent = null;
953
        for (TaxonNode node : acceptedTaxon.getTaxonNodes()){
954
            if (classificationUuid.equals(node.getClassification().getUuid())){
955
                parent = node.getParent();
956
            }
957
        }
958
        if (parent != null){
959
            return parent.getTaxon();
960
        }
961
        return null;
962
    }
963

    
964
    private void handleAncestorsForMarkersRecursive(TaxonInContextDTO result, List<MarkerType> markerTypes, TaxonNode node) {
965
       for (MarkerType type : markerTypes){
966
            Taxon taxon = node.getTaxon();
967
            if (taxon != null && taxon.hasMarker(type, true)){
968
                String label =  taxon.getName() == null? taxon.getTitleCache() : taxon.getName().getTitleCache();
969
                MarkedEntityDTO<Taxon> dto = new MarkedEntityDTO<>(type, true, taxon.getUuid(), label);
970
                result.addMarkedAncestor(dto);
971
            }
972
        }
973
        TaxonNode parentNode = node.getParent();
974
        if (parentNode != null){
975
            handleAncestorsForMarkersRecursive(result, markerTypes, parentNode);
976
        }
977
    }
978

    
979
    @Override
980
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
981
            Classification classification) {
982
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, false);
983
    }
984

    
985
    @Override
986
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
987
            UUID classificationUuid) {
988
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classificationUuid, false);
989
    }
990

    
991
    @Override
992
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
993
            UUID classificationUuid, Integer limit, String pattern) {
994
        return  getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classificationUuid,  limit, pattern, false);
995
    }
996

    
997
    @Override
998
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
999
            Classification classification, Integer limit, String pattern) {
1000
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, limit, pattern, false);
1001
    }
1002

    
1003
    @Override
1004
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1005
            UUID classificationUuid, Integer limit, String pattern, boolean searchForClassifications) {
1006
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1007
                classificationUuid, limit, pattern, searchForClassifications, false);
1008
    }
1009
}
(5-5/97)