Project

General

Profile

Download (45.4 KB) Statistics
| Branch: | Tag: | Revision:
1 01c21ead n.hoffmann
/**
2
* Copyright (C) 2007 EDIT
3 1ae9f0ff Andreas Kohlbecker
* European Distributed Institute of Taxonomy
4 01c21ead n.hoffmann
* http://www.e-taxonomy.eu
5 1ae9f0ff Andreas Kohlbecker
*
6 01c21ead n.hoffmann
* 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 b296585f Andreas Müller
import java.util.Arrays;
14 01c21ead n.hoffmann
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.Comparator;
17 48dde342 Alexander Oppermann
import java.util.HashMap;
18 e3fc5af3 Andreas Müller
import java.util.HashSet;
19 01c21ead n.hoffmann
import java.util.List;
20
import java.util.Map;
21 e3fc5af3 Andreas Müller
import java.util.Set;
22 01c21ead n.hoffmann
import java.util.TreeMap;
23
import java.util.UUID;
24
25 d8c4f8b9 Andreas Müller
import javax.persistence.EntityNotFoundException;
26
27 48dde342 Alexander Oppermann
import org.apache.commons.collections.CollectionUtils;
28 d8c4f8b9 Andreas Müller
import org.apache.commons.lang.StringUtils;
29 01c21ead n.hoffmann
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 48dde342 Alexander Oppermann
import eu.etaxonomy.cdm.api.service.config.CreateHierarchyForClassificationConfigurator;
35 969dbe3e Katja Luther
import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;
36
import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
37 d17b9e90 Andreas Müller
import eu.etaxonomy.cdm.api.service.dto.EntityDTO;
38 63f513d9 Andreas Müller
import eu.etaxonomy.cdm.api.service.dto.GroupedTaxonDTO;
39 4f290ba6 Andreas Müller
import eu.etaxonomy.cdm.api.service.dto.MarkedEntityDTO;
40 d17b9e90 Andreas Müller
import eu.etaxonomy.cdm.api.service.dto.TaxonInContextDTO;
41 dba75be8 Andreas Kohlbecker
import eu.etaxonomy.cdm.api.service.pager.Pager;
42
import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
43 7ff16b32 Andreas Kohlbecker
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
44 dba75be8 Andreas Kohlbecker
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
45 79c0eaa0 Andreas Müller
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
46 1251ffed Andreas Müller
import eu.etaxonomy.cdm.exception.FilterException;
47 cac97126 Andreas Müller
import eu.etaxonomy.cdm.exception.UnpublishedException;
48 c960706c Katja Luther
import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
49 355c89cb Patrick Plitzner
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
50 6b5ba3cc Andreas Kohlbecker
import eu.etaxonomy.cdm.model.common.CdmBase;
51 4f290ba6 Andreas Müller
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
52 63f513d9 Andreas Müller
import eu.etaxonomy.cdm.model.common.ITreeNode;
53 4f290ba6 Andreas Müller
import eu.etaxonomy.cdm.model.common.MarkerType;
54 e3fc5af3 Andreas Müller
import eu.etaxonomy.cdm.model.common.TreeIndex;
55 01c21ead n.hoffmann
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 892efc69 Andreas Kohlbecker
import eu.etaxonomy.cdm.model.media.MediaUtils;
60 a4c9dfc9 Andreas Müller
import eu.etaxonomy.cdm.model.name.INonViralName;
61 01c21ead n.hoffmann
import eu.etaxonomy.cdm.model.name.Rank;
62 9dc896c9 Andreas Müller
import eu.etaxonomy.cdm.model.name.TaxonName;
63 355c89cb Patrick Plitzner
import eu.etaxonomy.cdm.model.reference.Reference;
64 22697c60 Andreas Müller
import eu.etaxonomy.cdm.model.taxon.Classification;
65 8de80607 Andreas Kohlbecker
import eu.etaxonomy.cdm.model.taxon.ITaxonNodeComparator;
66 f6c2e10f Andreas Müller
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
67 d17b9e90 Andreas Müller
import eu.etaxonomy.cdm.model.taxon.Synonym;
68 01c21ead n.hoffmann
import eu.etaxonomy.cdm.model.taxon.Taxon;
69 d17b9e90 Andreas Müller
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
70 01c21ead n.hoffmann
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
71 355c89cb Patrick Plitzner
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
72 4f290ba6 Andreas Müller
import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
73 b9cbcc7c Andreas Kohlbecker
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
74 22697c60 Andreas Müller
import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;
75 01c21ead n.hoffmann
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
76
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
77 2b92f449 Andreas Kohlbecker
import eu.etaxonomy.cdm.persistence.dto.ClassificationLookupDTO;
78 d17b9e90 Andreas Müller
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
79 d8c4f8b9 Andreas Müller
import eu.etaxonomy.cdm.persistence.dto.TaxonStatus;
80 d26d6619 Andreas M��ller
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
81 01c21ead n.hoffmann
import eu.etaxonomy.cdm.persistence.query.OrderHint;
82 f197a589 Andreas Müller
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
83 48dde342 Alexander Oppermann
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
84 01c21ead n.hoffmann
85
/**
86
 * @author n.hoffmann
87 a88578ce Andreas Müller
 * @since Sep 21, 2009
88 01c21ead n.hoffmann
 */
89
@Service
90 77b4a247 Andreas Kohlbecker
@Transactional(readOnly = true)
91 4820d02b Andreas Müller
public class ClassificationServiceImpl
92
             extends IdentifiableServiceBase<Classification, IClassificationDao>
93
             implements IClassificationService {
94 1ae9f0ff Andreas Kohlbecker
    private static final Logger logger = Logger.getLogger(ClassificationServiceImpl.class);
95
96
    @Autowired
97
    private ITaxonNodeDao taxonNodeDao;
98 f2889751 Andreas Kohlbecker
99 1ae9f0ff Andreas Kohlbecker
    @Autowired
100
    private ITaxonDao taxonDao;
101 f2889751 Andreas Kohlbecker
102 d17b9e90 Andreas Müller
    @Autowired
103
    private ITaxonNodeService taxonNodeService;
104
105 4f290ba6 Andreas Müller
    @Autowired
106
    private IDefinedTermDao termDao;
107
108 1ae9f0ff Andreas Kohlbecker
    @Autowired
109
    private IBeanInitializer defaultBeanInitializer;
110 f2889751 Andreas Kohlbecker
111
    @Override
112 25461b19 Andreas Müller
    @Autowired
113
    protected void setDao(IClassificationDao dao) {
114
        this.dao = dao;
115
    }
116 f2889751 Andreas Kohlbecker
117 1ae9f0ff Andreas Kohlbecker
    private Comparator<? super TaxonNode> taxonNodeComparator;
118 f2889751 Andreas Kohlbecker
119 1ae9f0ff Andreas Kohlbecker
    @Autowired
120
    public void setTaxonNodeComparator(ITaxonNodeComparator<? super TaxonNode> taxonNodeComparator){
121
        this.taxonNodeComparator = (Comparator<? super TaxonNode>) taxonNodeComparator;
122
    }
123
124 dba75be8 Andreas Kohlbecker
    @Override
125 1ae9f0ff Andreas Kohlbecker
    public TaxonNode loadTaxonNodeByTaxon(Taxon taxon, UUID classificationUuid, List<String> propertyPaths){
126
        Classification tree = dao.load(classificationUuid);
127
        TaxonNode node = tree.getNode(taxon);
128
129
        return loadTaxonNode(node.getUuid(), propertyPaths);
130
    }
131
132
    public TaxonNode loadTaxonNode(UUID taxonNodeUuid, List<String> propertyPaths){
133
        return taxonNodeDao.load(taxonNodeUuid, propertyPaths);
134
    }
135
136 355c89cb Patrick Plitzner
    @Override
137
    @Transactional(readOnly = false)
138
    public UpdateResult cloneClassification(UUID classificationUuid,
139
    		String name, Reference sec, TaxonRelationshipType relationshipType) {
140
        UpdateResult result = new UpdateResult();
141
    	Classification classification = load(classificationUuid);
142
    	Classification clone = Classification.NewInstance(name);
143
    	clone.setReference(sec);
144
145
    	//clone taxa and taxon nodes
146
    	List<TaxonNode> childNodes = classification.getRootNode().getChildNodes();
147
    	for (TaxonNode taxonNode : childNodes) {
148
    		addChildTaxa(taxonNode, null, clone, relationshipType);
149
    	}
150
    	dao.saveOrUpdate(clone);
151
    	result.setCdmEntity(clone);
152
    	return result;
153
    }
154
155
    private void addChildTaxa(TaxonNode originalParentNode, TaxonNode cloneParentNode, Classification classification, TaxonRelationshipType relationshipType){
156 8fb27488 Patrick Plitzner
        Reference reference = classification.getReference();
157 355c89cb Patrick Plitzner
    	Taxon cloneTaxon = (Taxon) HibernateProxyHelper.deproxy(originalParentNode.getTaxon(), Taxon.class).clone();
158 8fb27488 Patrick Plitzner
    	cloneTaxon.setSec(reference);
159 355c89cb Patrick Plitzner
		String microReference = null;
160 66e8ec64 Patrick Plitzner
		List<TaxonNode> originalChildNodes = originalParentNode.getChildNodes();
161 c960706c Katja Luther
		HHH_9751_Util.removeAllNull(originalChildNodes);
162 355c89cb Patrick Plitzner
163
		//add relation between taxa
164 ae5a0d99 Andreas Müller
		if (relationshipType != null){
165
		    cloneTaxon.addTaxonRelation(originalParentNode.getTaxon(), relationshipType, reference, microReference);
166
		}
167 355c89cb Patrick Plitzner
168
		TaxonNode cloneChildNode = null;
169
    	//add taxon node to either parent node or classification (no parent node)
170
    	if(cloneParentNode==null){
171
    		cloneChildNode = classification.addChildTaxon(cloneTaxon, reference, microReference);
172
    	}
173
    	else{
174
    		cloneChildNode = cloneParentNode.addChildTaxon(cloneTaxon, reference, microReference);
175
    	}
176 66e8ec64 Patrick Plitzner
    	taxonNodeDao.saveOrUpdate(cloneChildNode);
177 355c89cb Patrick Plitzner
    	//add children
178 66e8ec64 Patrick Plitzner
		for (TaxonNode originalChildNode : originalChildNodes) {
179 355c89cb Patrick Plitzner
    		addChildTaxa(originalChildNode, cloneChildNode, classification, relationshipType);
180
    	}
181
    }
182
183 185155f8 Andreas Müller
    @Override
184
    public List<TaxonNode> listRankSpecificRootNodes(Classification classification, Rank rank,
185
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
186 cc1a7529 Andreas Müller
        return listRankSpecificRootNodes(classification, null, rank, includeUnpublished, pageSize, pageIndex, propertyPaths);
187 185155f8 Andreas Müller
    }
188
189 62a08491 Andreas Müller
    /**
190
     * {@inheritDoc}
191
     */
192 dba75be8 Andreas Kohlbecker
    @Override
193 185155f8 Andreas Müller
    public List<TaxonNode> listRankSpecificRootNodes(Classification classification,
194
            TaxonNode subtree, Rank rank,
195 62a08491 Andreas Müller
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
196 185155f8 Andreas Müller
        return pageRankSpecificRootNodes(classification, subtree, rank, includeUnpublished, pageSize, pageIndex, propertyPaths).getRecords();
197 dba75be8 Andreas Kohlbecker
    }
198
199
    @Override
200 62a08491 Andreas Müller
    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, Rank rank,
201
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
202 185155f8 Andreas Müller
        return pageRankSpecificRootNodes(classification, null, rank, includeUnpublished, pageSize, pageIndex, propertyPaths);
203
    }
204
205
    @Override
206
    public Pager<TaxonNode> pageRankSpecificRootNodes(Classification classification, TaxonNode subtree, Rank rank,
207
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) {
208
        long[] numberOfResults = dao.countRankSpecificRootNodes(classification, subtree, includeUnpublished, rank);
209 7ff16b32 Andreas Kohlbecker
        long totalNumberOfResults = numberOfResults[0] + (numberOfResults.length > 1 ? numberOfResults[1] : 0);
210 dba75be8 Andreas Kohlbecker
211 62a08491 Andreas Müller
        List<TaxonNode> results = new ArrayList<>();
212 dba75be8 Andreas Kohlbecker
213 7ff16b32 Andreas Kohlbecker
        if (AbstractPagerImpl.hasResultsInRange(totalNumberOfResults, pageIndex, pageSize)) { // no point checking again
214
            Integer limit = PagerUtils.limitFor(pageSize);
215
            Integer start = PagerUtils.startFor(pageSize, pageIndex);
216
217
            Integer remainingLimit = limit;
218
            int[] queryIndexes = rank == null ? new int[]{0} : new int[]{0,1};
219
220
            for(int queryIndex: queryIndexes) {
221
                if(start != null && start > numberOfResults[queryIndex]) {
222
                    // start in next query with new start value
223
                    start = start - (int)numberOfResults[queryIndex];
224
                    continue;
225
                }
226
227 62a08491 Andreas Müller
                List<TaxonNode> perQueryResults = dao.listRankSpecificRootNodes(classification,
228 185155f8 Andreas Müller
                        subtree, rank, includeUnpublished, remainingLimit,
229
                        start, propertyPaths, queryIndex);
230 7ff16b32 Andreas Kohlbecker
                results.addAll(perQueryResults);
231
                if(remainingLimit != null ){
232
                    remainingLimit = remainingLimit - results.size();
233
                    if(remainingLimit <= 0) {
234
                        // no need to run further queries if first query returned enough items!
235
                        break;
236
                    }
237
                    // start at with fist item of next query to fetch the remaining items
238
                    start = 0;
239
                }
240
            }
241 dba75be8 Andreas Kohlbecker
        }
242 f36a0784 Andreas Kohlbecker
//        long start_t = System.currentTimeMillis();
243 256c8f84 Andreas Kohlbecker
        Collections.sort(results, taxonNodeComparator); // TODO is ordering during the hibernate query in the dao possible?
244 f36a0784 Andreas Kohlbecker
//        System.err.println("service.pageRankSpecificRootNodes() - Collections.sort(results,  taxonNodeComparator) " + (System.currentTimeMillis() - start_t));
245 281a5d27 Andreas Müller
        return new DefaultPagerImpl<>(pageIndex, totalNumberOfResults, pageSize, results);
246 dba75be8 Andreas Kohlbecker
247
    }
248
249 d0df75bd Andreas Müller
    @Override
250
    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, Rank baseRank,
251
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
252
        return loadTreeBranch(taxonNode, null, baseRank, includeUnpublished, propertyPaths);
253
    }
254 cac97126 Andreas Müller
255 1ae9f0ff Andreas Kohlbecker
    /**
256 cac97126 Andreas Müller
     * {@inheritDoc}
257 1ae9f0ff Andreas Kohlbecker
     */
258 dba75be8 Andreas Kohlbecker
    @Override
259 d0df75bd Andreas Müller
    public List<TaxonNode> loadTreeBranch(TaxonNode taxonNode, TaxonNode subtree, Rank baseRank,
260 cac97126 Andreas Müller
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
261 1ae9f0ff Andreas Kohlbecker
262
        TaxonNode thisNode = taxonNodeDao.load(taxonNode.getUuid(), propertyPaths);
263 c8363cf5 Andreas Kohlbecker
        if(baseRank != null){
264
            baseRank = (Rank) termDao.load(baseRank.getUuid());
265
        }
266 df72b543 Andreas Müller
        if (!includeUnpublished && thisNode.getTaxon() != null && !thisNode.getTaxon().isPublish()){
267 cac97126 Andreas Müller
            throw new UnpublishedException("Final taxon in tree branch is unpublished.");
268
        }
269
270
        List<TaxonNode> pathToRoot = new ArrayList<>();
271 3f6e7646 Andreas Kohlbecker
        pathToRoot.add(thisNode);
272 1ae9f0ff Andreas Kohlbecker
273 1b880bc7 Andreas Kohlbecker
        while(!thisNode.isTopmostNode()){
274 6b5ba3cc Andreas Kohlbecker
            //TODO why do we need to deproxy here?
275 d919773a Andreas Kohlbecker
            //     without this thisNode.getParent() will return NULL in
276
            //     some cases (environment dependend?) even if the parent exits
277 cac97126 Andreas Müller
            TaxonNode parentNode = CdmBase.deproxy(thisNode).getParent();
278 5b16dccb Andreas Kohlbecker
279
            if(parentNode == null){
280 cac97126 Andreas Müller
                throw new NullPointerException("Taxon node " + thisNode + " must have a parent since it is not top most");
281 5b16dccb Andreas Kohlbecker
            }
282
            if(parentNode.getTaxon() == null){
283 cac97126 Andreas Müller
                throw new NullPointerException("The taxon associated with taxon node " + parentNode + " is NULL");
284
            }
285
            if(!includeUnpublished && !parentNode.getTaxon().isPublish()){
286
                throw new UnpublishedException("Some taxon in tree branch is unpublished.");
287 5b16dccb Andreas Kohlbecker
            }
288
            if(parentNode.getTaxon().getName() == null){
289
                throw new NullPointerException("The name of the taxon associated with taxonNode " + parentNode + " is NULL");
290
            }
291
292 cac97126 Andreas Müller
            Rank parentNodeRank = (parentNode.getTaxon().getName() == null) ? null : parentNode.getTaxon().getName().getRank();
293 1ae9f0ff Andreas Kohlbecker
            // stop if the next parent is higher than the baseRank
294 29abeaf8 Andreas Müller
            if(baseRank != null && parentNodeRank != null && baseRank.isLower(parentNodeRank)){
295 1ae9f0ff Andreas Kohlbecker
                break;
296
            }
297 d0df75bd Andreas Müller
            if((subtree!= null && !subtree.isAncestor(parentNode) )){
298
                break;
299
            }
300 5b16dccb Andreas Kohlbecker
301
            pathToRoot.add(parentNode);
302
            thisNode = parentNode;
303 1ae9f0ff Andreas Kohlbecker
        }
304
305
        // initialize and invert order of nodes in list
306
        defaultBeanInitializer.initializeAll(pathToRoot, propertyPaths);
307
        Collections.reverse(pathToRoot);
308
309
        return pathToRoot;
310
    }
311
312 dba75be8 Andreas Kohlbecker
    @Override
313 cac97126 Andreas Müller
    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification, Rank baseRank,
314
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
315 d0df75bd Andreas Müller
        return loadTreeBranchToTaxon(taxon, classification, null, baseRank, includeUnpublished, propertyPaths);
316
    }
317
318
    @Override
319 619ccb21 Andreas Müller
    public List<TaxonNode> loadTreeBranchToTaxon(Taxon taxon, Classification classification,
320
            TaxonNode subtree, Rank baseRank,
321 d0df75bd Andreas Müller
            boolean includeUnpublished, List<String> propertyPaths) throws UnpublishedException{
322 cac97126 Andreas Müller
323
        UUID nodeUuid = getTaxonNodeUuidByTaxonUuid(classification.getUuid(), taxon.getUuid());
324
        TaxonNode node = taxonNodeService.find(nodeUuid);
325 1ae9f0ff Andreas Kohlbecker
        if(node == null){
326
            logger.warn("The specified taxon is not found in the given tree.");
327
            return null;
328 619ccb21 Andreas Müller
        }else if (subtree != null && !node.isDescendant(subtree)){
329 d0df75bd Andreas Müller
            //TODO handle as exception? E.g. FilterException, AccessDeniedException?
330
            logger.warn("The specified taxon is not found for the given subtree.");
331
            return null;
332 1ae9f0ff Andreas Kohlbecker
        }
333 d0df75bd Andreas Müller
334
        return loadTreeBranch(node, subtree, baseRank, includeUnpublished, propertyPaths);
335 1ae9f0ff Andreas Kohlbecker
    }
336
337
338 dba75be8 Andreas Kohlbecker
    @Override
339 1ae9f0ff Andreas Kohlbecker
    public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
340
            List<String> propertyPaths) {
341
        taxonNode = taxonNodeDao.load(taxonNode.getUuid());
342
        List<TaxonNode> childNodes = new ArrayList<TaxonNode>(taxonNode.getChildNodes());
343
        defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
344
        Collections.sort(childNodes, taxonNodeComparator);
345
        return childNodes;
346
    }
347
348 dba75be8 Andreas Kohlbecker
    @Override
349 16fe90fd Andreas Müller
    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid,
350
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths){
351 1251ffed Andreas Müller
        try {
352
            return listChildNodesOfTaxon(taxonUuid, classificationUuid, null, includeUnpublished, pageSize, pageIndex, propertyPaths);
353
        } catch (FilterException e) {
354
            throw new RuntimeException(e);  //this should not happen as filter is null
355
        }
356 d0df75bd Andreas Müller
    }
357
358
    @Override
359
    public List<TaxonNode> listChildNodesOfTaxon(UUID taxonUuid, UUID classificationUuid, UUID subtreeUuid,
360 1251ffed Andreas Müller
            boolean includeUnpublished, Integer pageSize, Integer pageIndex, List<String> propertyPaths) throws FilterException{
361 f989e265 Andreas Kohlbecker
362 ba84f3fd Andreas Kohlbecker
        Classification classification = dao.load(classificationUuid);
363
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
364 1251ffed Andreas Müller
        TaxonNode subtree = taxonNodeDao.load(subtreeUuid);
365
        if (subtreeUuid != null && subtree == null){
366
            throw new FilterException("Taxon node for subtree filter can not be found in database", true);
367
        }
368 1ae9f0ff Andreas Kohlbecker
369 16fe90fd Andreas Müller
        List<TaxonNode> results = dao.listChildrenOf(
370 1251ffed Andreas Müller
                taxon, classification, subtree, includeUnpublished, pageSize, pageIndex, propertyPaths);
371 911a8140 Alexander Oppermann
        Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
372
        return results;
373 1ae9f0ff Andreas Kohlbecker
    }
374
375 183973c8 Andreas Kohlbecker
    @Override
376 e073fc85 Andreas Müller
    public Pager<TaxonNode> pageSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, boolean includeUnpublished,
377
            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
378 183973c8 Andreas Kohlbecker
379
        Classification classification = dao.load(classificationUuid);
380
        Taxon taxon = (Taxon) taxonDao.load(taxonUuid);
381
382 e073fc85 Andreas Müller
        long numberOfResults = dao.countSiblingsOf(taxon, classification, includeUnpublished);
383 183973c8 Andreas Kohlbecker
384
        List<TaxonNode> results;
385
        if(PagerUtils.hasResultsInRange(numberOfResults, pageIndex, pageSize)) {
386 e073fc85 Andreas Müller
            results = dao.listSiblingsOf(taxon, classification, includeUnpublished, pageSize, pageIndex, propertyPaths);
387 183973c8 Andreas Kohlbecker
            Collections.sort(results, taxonNodeComparator); // FIXME this is only a HACK, order during the hibernate query in the dao
388
        } else {
389
            results = new ArrayList<>();
390
        }
391
392 281a5d27 Andreas Müller
        return new DefaultPagerImpl<>(pageIndex, numberOfResults, pageSize, results);
393 183973c8 Andreas Kohlbecker
    }
394
395
    @Override
396 e073fc85 Andreas Müller
    public List<TaxonNode> listSiblingsOfTaxon(UUID taxonUuid, UUID classificationUuid, boolean includeUnpublished,
397
            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
398 183973c8 Andreas Kohlbecker
399 e073fc85 Andreas Müller
        Pager<TaxonNode> pager = pageSiblingsOfTaxon(taxonUuid, classificationUuid, includeUnpublished, pageSize, pageIndex, propertyPaths);
400 183973c8 Andreas Kohlbecker
        return pager.getRecords();
401
    }
402
403 dba75be8 Andreas Kohlbecker
    @Override
404 f6c2e10f Andreas Müller
    public ITaxonTreeNode getTreeNodeByUuid(UUID uuid){
405
        ITaxonTreeNode treeNode = taxonNodeDao.findByUuid(uuid);
406 1ae9f0ff Andreas Kohlbecker
        if(treeNode == null){
407
            treeNode = dao.findByUuid(uuid);
408
        }
409
410
        return treeNode;
411
    }
412
413 580b83e6 Patrick Plitzner
    @Override
414
    public TaxonNode getRootNode(UUID classificationUuid){
415
        return dao.getRootNode(classificationUuid);
416
    }
417
418 dba75be8 Andreas Kohlbecker
    @Override
419 1ae9f0ff Andreas Kohlbecker
    public List<Classification> listClassifications(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
420
        return dao.list(limit, start, orderHints, propertyPaths);
421
    }
422
423 dba75be8 Andreas Kohlbecker
    @Override
424 1ae9f0ff Andreas Kohlbecker
    public UUID removeTaxonNode(TaxonNode taxonNode) {
425
        return taxonNodeDao.delete(taxonNode);
426
    }
427 dba75be8 Andreas Kohlbecker
    @Override
428 f6c2e10f Andreas Müller
    public UUID removeTreeNode(ITaxonTreeNode treeNode) {
429 1ae9f0ff Andreas Kohlbecker
        if(treeNode instanceof Classification){
430
            return dao.delete((Classification) treeNode);
431
        }else if(treeNode instanceof TaxonNode){
432
            return taxonNodeDao.delete((TaxonNode)treeNode);
433
        }
434
        return null;
435
    }
436 dba75be8 Andreas Kohlbecker
    @Override
437 1ae9f0ff Andreas Kohlbecker
    public UUID saveTaxonNode(TaxonNode taxonNode) {
438 26b857a9 Cherian Mathew
        return taxonNodeDao.save(taxonNode).getUuid();
439 1ae9f0ff Andreas Kohlbecker
    }
440
441 dba75be8 Andreas Kohlbecker
    @Override
442 1ae9f0ff Andreas Kohlbecker
    public Map<UUID, TaxonNode> saveTaxonNodeAll(
443
            Collection<TaxonNode> taxonNodeCollection) {
444
        return taxonNodeDao.saveAll(taxonNodeCollection);
445
    }
446
447 08a698af Katja Luther
    @Override
448
    public UUID saveClassification(Classification classification) {
449
450
       taxonNodeDao.saveOrUpdateAll(classification.getAllNodes());
451
       UUID result =dao.saveOrUpdate(classification);
452
       return result;
453
    }
454
455 dba75be8 Andreas Kohlbecker
    @Override
456 f6c2e10f Andreas Müller
    public UUID saveTreeNode(ITaxonTreeNode treeNode) {
457 1ae9f0ff Andreas Kohlbecker
        if(treeNode instanceof Classification){
458 26b857a9 Cherian Mathew
            return dao.save((Classification) treeNode).getUuid();
459 1ae9f0ff Andreas Kohlbecker
        }else if(treeNode instanceof TaxonNode){
460 26b857a9 Cherian Mathew
            return taxonNodeDao.save((TaxonNode)treeNode).getUuid();
461 1ae9f0ff Andreas Kohlbecker
        }
462
        return null;
463
    }
464
465 dba75be8 Andreas Kohlbecker
    @Override
466 1ae9f0ff Andreas Kohlbecker
    public List<TaxonNode> getAllNodes(){
467
        return taxonNodeDao.list(null,null);
468
    }
469
470 001595b1 Katja Luther
    @Override
471 8e9115f6 Katja Luther
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, Integer limit, String pattern, boolean searchForClassifications) {
472
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid),  limit, pattern, searchForClassifications);
473 001595b1 Katja Luther
    }
474
475
    @Override
476 8e9115f6 Katja Luther
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification,  Integer limit, String pattern, boolean searchForClassifications) {
477
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification,  limit, pattern, searchForClassifications);
478 001595b1 Katja Luther
    }
479
480 818208b8 Cherian Mathew
    @Override
481 8e9115f6 Katja Luther
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(UUID classificationUuid, boolean searchForClassifications ) {
482
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(dao.load(classificationUuid), null, null, searchForClassifications);
483 818208b8 Cherian Mathew
    }
484
485 dba75be8 Andreas Kohlbecker
    @Override
486 8e9115f6 Katja Luther
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, boolean searchForClassifications ) {
487
        return taxonNodeDao.getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, null, null, searchForClassifications);
488 1ae9f0ff Andreas Kohlbecker
    }
489
490
    @Override
491 001595b1 Katja Luther
    public List<UuidAndTitleCache<Classification>> getUuidAndTitleCache(Integer limit, String pattern) {
492
        return dao.getUuidAndTitleCache(limit, pattern);
493 1ae9f0ff Andreas Kohlbecker
    }
494
495 dba75be8 Andreas Kohlbecker
    @Override
496 1ae9f0ff Andreas Kohlbecker
    public Map<UUID, List<MediaRepresentation>> getAllMediaForChildNodes(
497
            TaxonNode taxonNode, List<String> propertyPaths, int size,
498
            int height, int widthOrDuration, String[] mimeTypes) {
499
500 8c6a7c50 Andreas Müller
        TreeMap<UUID, List<MediaRepresentation>> result = new TreeMap<>();
501
        List<MediaRepresentation> mediaRepresentations = new ArrayList<>();
502 1ae9f0ff Andreas Kohlbecker
503
        //add all media of the children to the result map
504
        if (taxonNode != null){
505
506 8c6a7c50 Andreas Müller
            List<TaxonNode> nodes = new ArrayList<>();
507 1ae9f0ff Andreas Kohlbecker
508 8c6a7c50 Andreas Müller
            nodes.add(loadTaxonNode(taxonNode.getUuid(), propertyPaths));
509 1ae9f0ff Andreas Kohlbecker
            nodes.addAll(loadChildNodesOfTaxonNode(taxonNode, propertyPaths));
510
511 8c6a7c50 Andreas Müller
            for(TaxonNode node : nodes){
512
                Taxon taxon = node.getTaxon();
513
                for (TaxonDescription taxonDescription: taxon.getDescriptions()){
514
                    for (DescriptionElementBase descriptionElement: taxonDescription.getElements()){
515
                        for(Media media : descriptionElement.getMedia()){
516
                            //find the best matching representation
517
                            mediaRepresentations.add(MediaUtils.findBestMatchingRepresentation(media,null, size, height, widthOrDuration, mimeTypes));
518 1ae9f0ff Andreas Kohlbecker
                        }
519
                    }
520
                }
521 8c6a7c50 Andreas Müller
                result.put(taxon.getUuid(), mediaRepresentations);
522 1ae9f0ff Andreas Kohlbecker
            }
523
        }
524
525
        return result;
526
    }
527
528
    @Override
529
    @Transactional(readOnly = false)
530 57d5b579 Andreas Müller
    public void updateCaches(Class<? extends Classification> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<Classification> cacheStrategy, IProgressMonitor monitor) {
531 1ae9f0ff Andreas Kohlbecker
        if (clazz == null){
532
            clazz = Classification.class;
533
        }
534 784fe709 Andreas Müller
        super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
535 1ae9f0ff Andreas Kohlbecker
    }
536 f197a589 Andreas Müller
537 48dde342 Alexander Oppermann
    /**
538 dadec8d0 Alexander Oppermann
     *
539 48dde342 Alexander Oppermann
     * @param allNodesOfClassification
540
     * @return null - if  allNodesOfClassification is empty <br>
541
     */
542 dadec8d0 Alexander Oppermann
543 48dde342 Alexander Oppermann
    private Map<String, List<TaxonNode>> getSortedGenusList(Collection<TaxonNode> allNodesOfClassification){
544 dadec8d0 Alexander Oppermann
545 48dde342 Alexander Oppermann
    	if(allNodesOfClassification == null || allNodesOfClassification.isEmpty()){
546
    		return null;
547
    	}
548 a4c9dfc9 Andreas Müller
    	Map<String, List<TaxonNode>> sortedGenusMap = new HashMap<>();
549 48dde342 Alexander Oppermann
    	for(TaxonNode node:allNodesOfClassification){
550
    		Taxon taxon = node.getTaxon();
551 3d58795e Andreas Müller
    		INonViralName name = taxon.getName();
552 48dde342 Alexander Oppermann
    		String genusOrUninomial = name.getGenusOrUninomial();
553
    		//if rank unknown split string and take first word
554
    		if(genusOrUninomial == null){
555
    			String titleCache = taxon.getTitleCache();
556
    			String[] split = titleCache.split("\\s+");
557
    			for(String s:split){
558
    				genusOrUninomial = s;
559
    				break;
560
    			}
561
    		}
562
    		//if node has children
563 dadec8d0 Alexander Oppermann
564 48dde342 Alexander Oppermann
    		//retrieve list from map if not create List
565
    		if(sortedGenusMap.containsKey(genusOrUninomial)){
566
    			List<TaxonNode> list = sortedGenusMap.get(genusOrUninomial);
567
    			list.add(node);
568
    			sortedGenusMap.put(genusOrUninomial, list);
569
    		}else{
570
    			//create List for genus
571 8c6a7c50 Andreas Müller
    			List<TaxonNode> list = new ArrayList<>();
572 48dde342 Alexander Oppermann
    			list.add(node);
573
    			sortedGenusMap.put(genusOrUninomial, list);
574
    		}
575
    	}
576
    	return sortedGenusMap;
577
    }
578 f197a589 Andreas Müller
579 48dde342 Alexander Oppermann
    /**
580 dadec8d0 Alexander Oppermann
     *
581 48dde342 Alexander Oppermann
     * creates new Classification and parent TaxonNodes at genus level
582 dadec8d0 Alexander Oppermann
     *
583
     *
584 48dde342 Alexander Oppermann
     * @param map GenusMap which holds a name (Genus) and all the same Taxa as a list
585
     * @param classification you want to improve the hierarchy (will not be modified)
586 dadec8d0 Alexander Oppermann
     * @param configurator to change certain settings, if null then standard settings will be taken
587
     * @return new classification with parentNodes for each entry in the map
588 48dde342 Alexander Oppermann
     */
589 75f222cf Andreas Müller
    @SuppressWarnings({ "unchecked" })
590 48dde342 Alexander Oppermann
	@Transactional(readOnly = false)
591
	@Override
592 dadec8d0 Alexander Oppermann
    public UpdateResult createHierarchyInClassification(Classification classification, CreateHierarchyForClassificationConfigurator configurator){
593
        UpdateResult result = new UpdateResult();
594 48dde342 Alexander Oppermann
    	classification = dao.findByUuid(classification.getUuid());
595
    	Map<String, List<TaxonNode>> map = getSortedGenusList(classification.getAllNodes());
596 dadec8d0 Alexander Oppermann
597 48dde342 Alexander Oppermann
    	final String APPENDIX = "repaired";
598 75f222cf Andreas Müller
    	String titleCache = StringUtils.isBlank(classification.getTitleCache()) ? " " : classification.getTitleCache() ;
599 48dde342 Alexander Oppermann
    	//TODO classification clone???
600
    	Classification newClassification = Classification.NewInstance(titleCache +" "+ APPENDIX);
601
    	newClassification.setReference(classification.getReference());
602
603
    	for(Map.Entry<String, List<TaxonNode>> entry:map.entrySet()){
604
    		String genus = entry.getKey();
605
    		List<TaxonNode> listOfTaxonNodes = entry.getValue();
606
    		TaxonNode parentNode = null;
607 dadec8d0 Alexander Oppermann
    		//Search for genus in list
608 48dde342 Alexander Oppermann
    		for(TaxonNode tNode:listOfTaxonNodes){
609
    			//take that taxonNode as parent and remove from list with all it possible children
610
    			//FIXME NPE for name
611 9dc896c9 Andreas Müller
    			TaxonName name = tNode.getTaxon().getName();
612 a4c9dfc9 Andreas Müller
    			if(name.getNameCache().equalsIgnoreCase(genus)){
613 48dde342 Alexander Oppermann
    				TaxonNode clone = (TaxonNode) tNode.clone();
614
    				if(!tNode.hasChildNodes()){
615 dadec8d0 Alexander Oppermann
    					//FIXME remove classification
616 48dde342 Alexander Oppermann
//    					parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference());
617
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
618
    					//remove taxonNode from list because just added to classification
619 dadec8d0 Alexander Oppermann
    					result.addUpdatedObject(tNode);
620 48dde342 Alexander Oppermann
    					listOfTaxonNodes.remove(tNode);
621
    				}else{
622 dadec8d0 Alexander Oppermann
    					//get all childNodes
623 48dde342 Alexander Oppermann
    					//save prior Hierarchy and remove them from the list
624 dadec8d0 Alexander Oppermann
    					List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tNode, clone, result);
625 48dde342 Alexander Oppermann
//    					parentNode = newClassification.addChildNode(clone, 0, classification.getCitation(), classification.getMicroReference());
626
      					//FIXME remove classification
627
    					parentNode = newClassification.addChildNode(clone, 0, clone.getReference(), clone.getMicroReference());
628
    					//remove taxonNode from list because just added to classification
629 dadec8d0 Alexander Oppermann
    					result.addUpdatedObject(tNode);
630 48dde342 Alexander Oppermann
    					listOfTaxonNodes.remove(tNode);
631
    					if(copyAllChildrenToTaxonNode != null){
632
    						listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
633
    					}
634
    				}
635
    				break;
636
    			}
637
    		}
638
    		if(parentNode == null){
639
    			//if no match found in list, create parentNode
640
    			NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
641 db183545 Andreas Müller
    			TaxonName TaxonName = (TaxonName)parser.parseFullName(genus);
642 48dde342 Alexander Oppermann
    			//TODO Sec via configurator
643 9dc896c9 Andreas Müller
    			Taxon taxon = Taxon.NewInstance(TaxonName, null);
644 48dde342 Alexander Oppermann
    			parentNode = newClassification.addChildTaxon(taxon, 0, null, null);
645 dadec8d0 Alexander Oppermann
    			result.addUpdatedObject(parentNode);
646 48dde342 Alexander Oppermann
    		}
647
    		//iterate over the rest of the list
648
    		for(TaxonNode tn : listOfTaxonNodes){
649 dadec8d0 Alexander Oppermann
    			//if TaxonNode has a parent and this is not the classification then skip it
650 48dde342 Alexander Oppermann
    			//and add to new classification via the parentNode as children of it
651
    			//this should assures to keep the already existing hierarchy
652
    			//FIXME: Assert is not rootnode --> entrypoint is not classification in future but rather rootNode
653 dadec8d0 Alexander Oppermann
654 48dde342 Alexander Oppermann
    			if(!tn.isTopmostNode()){
655
    				continue; //skip to next taxonNode
656
    			}
657 dadec8d0 Alexander Oppermann
658 48dde342 Alexander Oppermann
    			TaxonNode clone = (TaxonNode) tn.clone();
659
    			//FIXME: citation from node
660
    			//TODO: addchildNode without citation and references
661
//    			TaxonNode taxonNode = parentNode.addChildNode(clone, classification.getCitation(), classification.getMicroReference());
662
    			TaxonNode taxonNode = parentNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
663 550710d2 Alexander Oppermann
    			result.addUnChangedObject(clone);
664 48dde342 Alexander Oppermann
    			if(tn.hasChildNodes()){
665
    				//save hierarchy in new classification
666 dadec8d0 Alexander Oppermann
    				List<TaxonNode> copyAllChildrenToTaxonNode = copyAllChildrenToTaxonNode(tn, taxonNode, result);
667 48dde342 Alexander Oppermann
    				if(copyAllChildrenToTaxonNode != null){
668
    					listOfTaxonNodes = (List<TaxonNode>) CollectionUtils.removeAll(listOfTaxonNodes, copyAllChildrenToTaxonNode);
669
    				}
670
    			}
671
    		}
672
    	}
673
    	dao.saveOrUpdate(newClassification);
674 dadec8d0 Alexander Oppermann
    	result.setCdmEntity(newClassification);
675
    	return result;
676 48dde342 Alexander Oppermann
    }
677
678
    /**
679 dadec8d0 Alexander Oppermann
     *
680 48dde342 Alexander Oppermann
     * recursive method to get all childnodes of taxonNode in classification.
681 dadec8d0 Alexander Oppermann
     *
682 48dde342 Alexander Oppermann
     * @param classification just for References and Citation, can be null
683
     * @param copyFromNode TaxonNode with Children
684
     * @param copyToNode TaxonNode which will receive the children
685 dadec8d0 Alexander Oppermann
     * @return List of ChildNode which has been added. If node has no children returns null
686 48dde342 Alexander Oppermann
     */
687 dadec8d0 Alexander Oppermann
   private List<TaxonNode> copyAllChildrenToTaxonNode(TaxonNode copyFromNode, TaxonNode copyToNode, UpdateResult result) {
688 48dde342 Alexander Oppermann
		List<TaxonNode> childNodes;
689
		if(!copyFromNode.hasChildNodes()){
690
			return null;
691
		}else{
692
			childNodes = copyFromNode.getChildNodes();
693
		}
694
		for(TaxonNode childNode:childNodes){
695
			TaxonNode clone = (TaxonNode) childNode.clone();
696 dadec8d0 Alexander Oppermann
			result.addUnChangedObject(clone);
697 48dde342 Alexander Oppermann
			if(childNode.hasChildNodes()){
698 dadec8d0 Alexander Oppermann
				copyAllChildrenToTaxonNode(childNode, clone, result);
699 48dde342 Alexander Oppermann
			}
700
			//FIXME: citation from node instead of classification
701
//			copyToNode.addChildNode(clone,classification.getCitation(), classification.getMicroReference());
702
			copyToNode.addChildNode(clone, clone.getReference(), clone.getMicroReference());
703
		}
704
		return childNodes;
705
	}
706 dadec8d0 Alexander Oppermann
707 357386e4 Andreas Müller
    /**
708 2b92f449 Andreas Kohlbecker
     * {@inheritDoc}
709
     */
710
    @Override
711 357386e4 Andreas Müller
    public ClassificationLookupDTO classificationLookup(Classification classification) {
712
        return dao.classificationLookup(classification);
713
    }
714 2b92f449 Andreas Kohlbecker
715 969dbe3e Katja Luther
716 357386e4 Andreas Müller
    @Override
717 b3efd136 Katja Luther
    @Transactional
718 969dbe3e Katja Luther
    public DeleteResult delete(UUID classificationUuid, TaxonDeletionConfigurator config){
719
        DeleteResult result = new DeleteResult();
720
        Classification classification = dao.findByUuid(classificationUuid);
721
        if (classification == null){
722
            result.addException(new IllegalArgumentException("The classification does not exist in database."));
723
            result.setAbort();
724
            return result;
725
        }
726
        if (!classification.hasChildNodes()){
727
            dao.delete(classification);
728 815a9015 Katja Luther
            result.addDeletedObject(classification);
729 b3efd136 Katja Luther
            return result;
730 969dbe3e Katja Luther
        }
731 b3efd136 Katja Luther
        if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)){
732 d8866c51 Katja Luther
//            TaxonNode root = classification.getRootNode();
733
//            result.includeResult(taxonNodeService.deleteTaxonNode(HibernateProxyHelper.deproxy(root), config));
734
//            result.addDeletedObject(classification);
735 969dbe3e Katja Luther
            dao.delete(classification);
736 815a9015 Katja Luther
            result.addDeletedObject(classification);
737 d8866c51 Katja Luther
            return result;
738 969dbe3e Katja Luther
        }
739
740
741
        return result;
742
    }
743
744 63f513d9 Andreas Müller
    @Override
745
    public List<GroupedTaxonDTO> groupTaxaByHigherTaxon(List<UUID> originalTaxonUuids, UUID classificationUuid, Rank minRank, Rank maxRank){
746
        List<GroupedTaxonDTO> result = new ArrayList<>();
747
748
        //get treeindex for each taxonUUID
749 e3fc5af3 Andreas Müller
        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
750 63f513d9 Andreas Müller
751 a8609cad Andreas Müller
        //build treeindex list (or tree)
752 e3fc5af3 Andreas Müller
        //TODO make it work with TreeIndex or move there
753
        List<String> treeIndexClosureStr = new ArrayList<>();
754
        for (TreeIndex treeIndex : taxonIdTreeIndexMap.values()){
755
            String[] splits = treeIndex.toString().substring(1).split(ITreeNode.separator);
756 63f513d9 Andreas Müller
            String currentIndex = ITreeNode.separator;
757
            for (String split : splits){
758
                if (split.equals("")){
759
                    continue;
760
                }
761
                currentIndex += split + ITreeNode.separator;
762 e3fc5af3 Andreas Müller
                if (!treeIndexClosureStr.contains(currentIndex) && !split.startsWith(ITreeNode.treePrefix)){
763
                    treeIndexClosureStr.add(currentIndex);
764 63f513d9 Andreas Müller
                }
765
            }
766
        }
767
768
        //get rank sortindex for all parent taxa with sortindex <= minRank and sortIndex >= maxRank (if available)
769 29a5f57c Andreas Müller
        Integer minRankOrderIndex = minRank == null ? null : minRank.getOrderIndex();
770
        Integer maxRankOrderIndex = maxRank == null ? null : maxRank.getOrderIndex();
771 e3fc5af3 Andreas Müller
        List<TreeIndex> treeIndexClosure = TreeIndex.NewListInstance(treeIndexClosureStr);
772
773
        Map<TreeIndex, Integer> treeIndexSortIndexMapTmp = taxonNodeDao.rankOrderIndexForTreeIndex(treeIndexClosure, minRankOrderIndex, maxRankOrderIndex);
774 63f513d9 Andreas Müller
775
        //remove all treeindex with "exists child in above map(and child.sortindex > xxx)
776 e3fc5af3 Andreas Müller
        List<TreeIndex> treeIndexList = TreeIndex.sort(treeIndexSortIndexMapTmp.keySet());
777
778
        Map<TreeIndex, Integer> treeIndexSortIndexMap = new HashMap<>();
779
        TreeIndex lastTreeIndex = null;
780
        for (TreeIndex treeIndex : treeIndexList){
781
            if (lastTreeIndex != null && lastTreeIndex.hasChild(treeIndex)){
782 63f513d9 Andreas Müller
                treeIndexSortIndexMap.remove(lastTreeIndex);
783
            }
784
            treeIndexSortIndexMap.put(treeIndex, treeIndexSortIndexMapTmp.get(treeIndex));
785
            lastTreeIndex = treeIndex;
786
        }
787
788
        //get taxonID for treeIndexes
789 e3fc5af3 Andreas Müller
        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(treeIndexSortIndexMap.keySet());
790 63f513d9 Andreas Müller
791
        //fill result list
792
        for (UUID originalTaxonUuid : originalTaxonUuids){
793
            GroupedTaxonDTO item = new GroupedTaxonDTO();
794
            result.add(item);
795
            item.setTaxonUuid(originalTaxonUuid);
796 e3fc5af3 Andreas Müller
            TreeIndex groupTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
797
            String groupIndexX = TreeIndex.toString(groupTreeIndex);
798
            while (groupTreeIndex != null){
799
                if (treeIndexTaxonIdMap.get(groupTreeIndex) != null){
800
                    UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
801 63f513d9 Andreas Müller
                    item.setGroupTaxonUuid(uuidAndLabel.getUuid());
802
                    item.setGroupTaxonName(uuidAndLabel.getTitleCache());
803
                    break;
804
                }else{
805 e3fc5af3 Andreas Müller
                    groupTreeIndex = groupTreeIndex.parent();
806
//                    int index = groupIndex.substring(0, groupIndex.length()-1).lastIndexOf(ITreeNode.separator);
807
//                    groupIndex = index < 0 ? null : groupIndex.substring(0, index+1);
808 63f513d9 Andreas Müller
                }
809
            }
810
        }
811
812
        return result;
813
    }
814
815 e3fc5af3 Andreas Müller
    /**
816
     * {@inheritDoc}
817
     */
818
    @Override
819
    public List<GroupedTaxonDTO> groupTaxaByMarkedParents(List<UUID> originalTaxonUuids, UUID classificationUuid,
820
            MarkerType markerType, Boolean flag) {
821
822
        List<GroupedTaxonDTO> result = new ArrayList<>();
823
824
        //get treeindex for each taxonUUID
825
        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
826
827
        //get all marked tree indexes
828
        Set<TreeIndex> markedTreeIndexes = dao.getMarkedTreeIndexes(markerType, flag);
829
830
831
        Map<TreeIndex, TreeIndex> groupedMap = TreeIndex.group(markedTreeIndexes, taxonIdTreeIndexMap.values());
832
        Set<TreeIndex> notNullGroups = new HashSet<>(groupedMap.values());
833
        notNullGroups.remove(null);
834
835
        //get taxonInfo for treeIndexes
836
        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(notNullGroups);
837
838
        //fill result list
839
        for (UUID originalTaxonUuid : originalTaxonUuids){
840
            GroupedTaxonDTO item = new GroupedTaxonDTO();
841
            result.add(item);
842
            item.setTaxonUuid(originalTaxonUuid);
843
844
            TreeIndex toBeGroupedTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
845
            TreeIndex groupTreeIndex = groupedMap.get(toBeGroupedTreeIndex);
846
            UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
847
            if (uuidAndLabel != null){
848
                item.setGroupTaxonUuid(uuidAndLabel.getUuid());
849
                item.setGroupTaxonName(uuidAndLabel.getTitleCache());
850
            }
851
        }
852
853
        return result;
854
    }
855
856 b296585f Andreas Müller
    /**
857
     * {@inheritDoc}
858
     */
859
    @Override
860
    public UUID getTaxonNodeUuidByTaxonUuid(UUID classificationUuid, UUID taxonUuid) {
861
        Map<UUID, UUID> map = dao.getTaxonNodeUuidByTaxonUuid(classificationUuid, Arrays.asList(taxonUuid));
862
        UUID taxonNodeUuid = map.get(taxonUuid);
863
        return taxonNodeUuid;
864
    }
865
866 d17b9e90 Andreas Müller
    /**
867
     * {@inheritDoc}
868
     */
869
    @Override
870 d8c4f8b9 Andreas Müller
    public TaxonInContextDTO getTaxonInContext(UUID classificationUuid, UUID taxonBaseUuid,
871 2edda1af Andreas Müller
            Boolean doChildren, Boolean doSynonyms, boolean includeUnpublished, List<UUID> ancestorMarkers,
872 d17b9e90 Andreas Müller
            NodeSortMode sortMode) {
873
        TaxonInContextDTO result = new TaxonInContextDTO();
874 d8c4f8b9 Andreas Müller
875
        TaxonBase<?> taxonBase = taxonDao.load(taxonBaseUuid);
876 1d54cd17 Andreas Müller
        if (taxonBase == null){
877 d8c4f8b9 Andreas Müller
            throw new EntityNotFoundException("Taxon with uuid " + taxonBaseUuid + " not found in datasource");
878
        }
879
        boolean isSynonym = false;
880
        Taxon acceptedTaxon;
881
        if (taxonBase.isInstanceOf(Synonym.class)){
882
            isSynonym = true;
883
            Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
884 f476ff86 Andreas Müller
            acceptedTaxon = synonym.getAcceptedTaxon();
885 d8c4f8b9 Andreas Müller
            if (acceptedTaxon == null) {
886
                throw new EntityNotFoundException("Accepted taxon not found for synonym"  );
887
            }
888
            TaxonStatus taxonStatus = TaxonStatus.Synonym;
889
            if (synonym.getName()!= null && acceptedTaxon.getName() != null
890
                    && synonym.getName().getHomotypicalGroup().equals(acceptedTaxon.getName().getHomotypicalGroup())){
891
                taxonStatus = TaxonStatus.SynonymObjective;
892
            }
893
            result.setTaxonStatus(taxonStatus);
894
895
        }else{
896
            acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
897
            result.setTaxonStatus(TaxonStatus.Accepted);
898
        }
899
        UUID acceptedTaxonUuid = acceptedTaxon.getUuid();
900
901
        UUID taxonNodeUuid = getTaxonNodeUuidByTaxonUuid(classificationUuid, acceptedTaxonUuid);
902
        if (taxonNodeUuid == null) {
903
            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 );
904
        }
905
        result.setTaxonNodeUuid(taxonNodeUuid);
906 cbae39d4 Andreas Müller
907
        //TODO make it a dao call
908
        Taxon parentTaxon = getParentTaxon(classificationUuid, acceptedTaxon);
909
        if (parentTaxon != null){
910
            result.setParentTaxonUuid(parentTaxon.getUuid());
911
            result.setParentTaxonLabel(parentTaxon.getTitleCache());
912
            if (parentTaxon.getName() != null){
913
                result.setParentNameLabel(parentTaxon.getName().getTitleCache());
914
            }
915
        }
916
917 d8c4f8b9 Andreas Müller
        result.setTaxonUuid(taxonBaseUuid);
918
        result.setClassificationUuid(classificationUuid);
919
        if (taxonBase.getSec() != null){
920
            result.setSecundumUuid(taxonBase.getSec().getUuid());
921
            result.setSecundumLabel(taxonBase.getSec().getTitleCache());
922 1d54cd17 Andreas Müller
        }
923 d8c4f8b9 Andreas Müller
        result.setTaxonLabel(taxonBase.getTitleCache());
924 d17b9e90 Andreas Müller
925 db183545 Andreas Müller
        TaxonName name = taxonBase.getName();
926 d17b9e90 Andreas Müller
        result.setNameUuid(name.getUuid());
927
        result.setNameLabel(name.getTitleCache());
928 a4c9dfc9 Andreas Müller
        result.setNameWithoutAuthor(name.getNameCache());
929
        result.setGenusOrUninomial(name.getGenusOrUninomial());
930
        result.setInfraGenericEpithet(name.getInfraGenericEpithet());
931
        result.setSpeciesEpithet(name.getSpecificEpithet());
932
        result.setInfraSpecificEpithet(name.getInfraSpecificEpithet());
933
934
        result.setAuthorship(name.getAuthorshipCache());
935
936
        Rank rank = name.getRank();
937
        if (rank != null){
938
            result.setRankUuid(rank.getUuid());
939
            String rankLabel = rank.getAbbreviation();
940
            if (StringUtils.isBlank(rankLabel)){
941
                rankLabel = rank.getLabel();
942 d17b9e90 Andreas Müller
            }
943 a4c9dfc9 Andreas Müller
            result.setRankLabel(rankLabel);
944 d17b9e90 Andreas Müller
        }
945
946
        boolean recursive = false;
947 4f290ba6 Andreas Müller
        Integer pageSize = null;
948
        Integer pageIndex = null;
949 2edda1af Andreas Müller
        Pager<TaxonNodeDto> children = taxonNodeService.pageChildNodesDTOs(taxonNodeUuid, recursive, includeUnpublished, doSynonyms,
950
                sortMode, pageSize, pageIndex);
951 d17b9e90 Andreas Müller
952
        //children
953 d8c4f8b9 Andreas Müller
        if(! isSynonym) {
954
            for (TaxonNodeDto childDto : children.getRecords()){
955
                if (doChildren && childDto.getStatus().equals(TaxonStatus.Accepted)){
956
                    EntityDTO<Taxon> child = new EntityDTO<Taxon>(childDto.getTaxonUuid(), childDto.getTitleCache());
957
                    result.addChild(child);
958
                }else if (doSynonyms && childDto.getStatus().isSynonym()){
959 281a5d27 Andreas Müller
                    EntityDTO<Synonym> child = new EntityDTO<>(childDto.getTaxonUuid(), childDto.getTitleCache());
960 d8c4f8b9 Andreas Müller
                    result.addSynonym(child);
961
                }
962 d17b9e90 Andreas Müller
            }
963 d8c4f8b9 Andreas Müller
        }else{
964
            result.setAcceptedTaxonUuid(acceptedTaxonUuid);
965
            String nameTitel = acceptedTaxon.getName() == null ? null : acceptedTaxon.getName().getTitleCache();
966
            result.setAcceptedTaxonLabel(acceptedTaxon.getTitleCache());
967
            result.setAcceptedNameLabel(nameTitel);
968 d17b9e90 Andreas Müller
        }
969
970
        //marked ancestors
971 1d54cd17 Andreas Müller
        if (ancestorMarkers != null && !ancestorMarkers.isEmpty()){
972 281a5d27 Andreas Müller
            @SuppressWarnings("rawtypes")
973 4f290ba6 Andreas Müller
            List<DefinedTermBase> markerTypesTerms = termDao.list(ancestorMarkers, pageSize, null, null, null);
974
            List<MarkerType> markerTypes = new ArrayList<>();
975
            for (DefinedTermBase<?> term : markerTypesTerms){
976
                if (term.isInstanceOf(MarkerType.class)){
977
                    markerTypes.add(CdmBase.deproxy(term, MarkerType.class));
978
                }
979
            }
980
            if (! markerTypes.isEmpty()){
981
                TaxonNode node = taxonNodeDao.findByUuid(taxonNodeUuid);
982
                handleAncestorsForMarkersRecursive(result, markerTypes, node);
983
            }
984
        }
985
986 d17b9e90 Andreas Müller
        return result;
987
    }
988
989 cbae39d4 Andreas Müller
    /**
990
     * @param classificationUuid
991
     * @param acceptedTaxon
992
     * @return
993
     */
994
    private Taxon getParentTaxon(UUID classificationUuid, Taxon acceptedTaxon) {
995
        if (classificationUuid == null){
996
            return null;
997
        }
998
        TaxonNode parent = null;
999
        for (TaxonNode node : acceptedTaxon.getTaxonNodes()){
1000
            if (classificationUuid.equals(node.getClassification().getUuid())){
1001
                parent = node.getParent();
1002
            }
1003
        }
1004
        if (parent != null){
1005
            return parent.getTaxon();
1006
        }
1007
        return null;
1008
    }
1009
1010 4f290ba6 Andreas Müller
    /**
1011
     * @param result
1012
     * @param markerTypes
1013
     * @param node
1014
     */
1015
    private void handleAncestorsForMarkersRecursive(TaxonInContextDTO result, List<MarkerType> markerTypes, TaxonNode node) {
1016
       for (MarkerType type : markerTypes){
1017
            Taxon taxon = node.getTaxon();
1018
            if (taxon != null && taxon.hasMarker(type, true)){
1019 d8c4f8b9 Andreas Müller
                String label =  taxon.getName() == null? taxon.getTitleCache() : taxon.getName().getTitleCache();
1020
                MarkedEntityDTO<Taxon> dto = new MarkedEntityDTO<>(type, true, taxon.getUuid(), label);
1021 4f290ba6 Andreas Müller
                result.addMarkedAncestor(dto);
1022
            }
1023
        }
1024
        TaxonNode parentNode = node.getParent();
1025
        if (parentNode != null){
1026
            handleAncestorsForMarkersRecursive(result, markerTypes, parentNode);
1027
        }
1028
    }
1029
1030 8e9115f6 Katja Luther
    /**
1031
     * {@inheritDoc}
1032
     */
1033
    @Override
1034
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1035
            Classification classification) {
1036
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, false);
1037
    }
1038
1039
    /**
1040
     * {@inheritDoc}
1041
     */
1042
    @Override
1043
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1044
            UUID classificationUuid) {
1045
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classificationUuid, false);
1046
    }
1047
1048
    /**
1049
     * {@inheritDoc}
1050
     */
1051
    @Override
1052
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1053
            UUID classificationUuid, Integer limit, String pattern) {
1054
        return  getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classificationUuid,  limit, pattern, false);
1055
    }
1056
1057
    /**
1058
     * {@inheritDoc}
1059
     */
1060
    @Override
1061
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(
1062
            Classification classification, Integer limit, String pattern) {
1063
        return getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(classification, limit, pattern, false);
1064
    }
1065 01c21ead n.hoffmann
}