Project

General

Profile

Revision e3fc5af3

IDe3fc5af3c712b705d2c5b4ee36b9334cedd1e710
Parent 9c4f03a5
Child 39811603

Added by Andreas Müller almost 5 years ago

fix #6134 add group taxa by marker and refactor treeindex handling

View differences:

cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/common/TreeIndex.java
1
/**
2
* Copyright (C) 2016 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
package eu.etaxonomy.cdm.model.common;
10

  
11
import java.util.ArrayList;
12
import java.util.Collection;
13
import java.util.Collections;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.regex.Pattern;
18

  
19
import eu.etaxonomy.cdm.model.description.FeatureNode;
20
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
21

  
22
/**
23
 * A class to handle tree indexes as used in {@link TaxonNode}, {@link FeatureNode}
24
 * etc.<BR>
25
 * Might be come a hibernate user type in future.
26
 *
27
 * @author a.mueller
28
 * @date 02.12.2016
29
 *
30
 */
31
public class TreeIndex {
32

  
33
    public static TreeIndex NewInstance(String treeIndex){
34
        return new TreeIndex(treeIndex);
35
    }
36

  
37

  
38
    /**
39
     * @param stringList
40
     * @return
41
     */
42
    public static List<TreeIndex> NewListInstance(List<String> stringList) {
43
        List<TreeIndex> result = new ArrayList<>();
44
        for (String string: stringList){
45
            result.add(new TreeIndex(string));
46
        }
47
        return result;
48
    }
49

  
50
    private static String regEx = "#[a-z](\\d+#)+";
51
    private static Pattern pattern = Pattern.compile(regEx);
52

  
53
    private static TreeIndexComparator comparator = new TreeIndexComparator();
54

  
55
    private String treeIndex;
56

  
57
    private TreeIndex(String treeIndex){
58
        if (! pattern.matcher(treeIndex).matches()){
59
            throw new IllegalArgumentException("Given string is not a valid tree index");
60
        }
61
        this.treeIndex = treeIndex;
62
    }
63

  
64
// ************** METHODS ***************************************/
65

  
66
    /**
67
     * @param taxonTreeIndex
68
     * @return
69
     */
70
    public boolean hasChild(TreeIndex childCandidateTreeIndex) {
71
        return childCandidateTreeIndex.treeIndex.startsWith(treeIndex);
72
    }
73

  
74

  
75
    /**
76
     * Returns a new TreeIndex instance which represents the parent of this tree index.
77
     * Returns null if this tree index already represents the root node of the tree.
78
     * @return
79
     */
80
    public TreeIndex parent(){
81
        int index = treeIndex.substring(0, treeIndex.length()-1).lastIndexOf(ITreeNode.separator);
82
        try {
83
            TreeIndex result = index < 0 ? null : NewInstance(treeIndex.substring(0, index+1));
84
            return result;
85
        } catch (Exception e) {
86
            //it is not a valid treeindex anymore
87
            return null;
88
        }
89
    }
90

  
91
// ********************** STATIC METHODS  *****************************/
92

  
93
    /**
94
     * Creates a list for the given tree indexes and sorts them in ascending
95
     * order.
96
     * @param treeIndexSet
97
     * @return
98
     */
99
    public static List<TreeIndex> sort(Collection<TreeIndex> treeIndexSet) {
100
        List<TreeIndex> result = new ArrayList<>(treeIndexSet);
101
        Collections.sort(result, comparator);
102
        return result;
103
    }
104

  
105

  
106
    /**
107
     * Creates a list for the given tree indexes and sorts them in descending
108
     * order.
109
     * @param treeIndexSet
110
     * @return
111
     */
112
    public static List<TreeIndex> sortDesc(Collection<TreeIndex> treeIndexSet) {
113
        List<TreeIndex> result = sort(treeIndexSet);
114
        Collections.reverse(result);
115
        return result;
116
    }
117

  
118
    public static Map<TreeIndex, TreeIndex> group(Collection<TreeIndex> groupingIndexes, Collection<TreeIndex> toBeGroupedIndexes){
119

  
120
        //for larger groupingIndexes we could optimize this by sorting both collections
121
        //prior to loop. This way we do traverse both lists once
122
        Map<TreeIndex, TreeIndex> result = new HashMap<>();
123
        List<TreeIndex> descSortedGroupingIndexes = sortDesc(groupingIndexes);
124

  
125
        for (TreeIndex toBeGrouped : toBeGroupedIndexes) {
126
            boolean groupFound = false;
127
            for (TreeIndex groupingIndex : descSortedGroupingIndexes){
128
                if (groupingIndex.hasChild(toBeGrouped)){
129
                    result.put(toBeGrouped, groupingIndex);
130
                    groupFound = true;
131
                    break;
132
                }
133
            }
134
            if (!groupFound){
135
                result.put(toBeGrouped, null);
136
            }
137
        }
138
        return result;
139
    }
140

  
141

  
142
// **************************** EQUALS *****************************/
143

  
144
    @Override
145
    public int hashCode() {
146
        return treeIndex.hashCode();
147
    }
148

  
149
    @Override
150
    public boolean equals(Object obj) {
151
        if (obj instanceof TreeIndex){
152
            return treeIndex.equals(((TreeIndex)obj).treeIndex);
153
        }else{
154
            return false;
155
        }
156
    }
157

  
158
// *************************** toString() ***********************
159

  
160

  
161

  
162
    @Override
163
    public String toString(){
164
        return treeIndex;
165
    }
166

  
167
    /**
168
     * Null save toString method.
169
     * @param treeIndex
170
     * @return
171
     */
172
    public static String toString(TreeIndex treeIndex) {
173
        return treeIndex == null? null: treeIndex.toString();
174
    }
175

  
176

  
177
    /**
178
     * @param treeIndexes
179
     * @return
180
     */
181
    public static List<String> toString(Collection<TreeIndex> treeIndexes) {
182
        List<String> result = new ArrayList<>();
183
        for (TreeIndex treeIndex : treeIndexes){
184
            result.add(treeIndex.toString());
185
        }
186
        return result;
187
    }
188

  
189
}
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/common/TreeIndexComparator.java
1
// $Id$
2
/**
3
* Copyright (C) 2016 EDIT
4
* European Distributed Institute of Taxonomy
5
* http://www.e-taxonomy.eu
6
*
7
* The contents of this file are subject to the Mozilla Public License Version 1.1
8
* See LICENSE.TXT at the top of this package for the full license terms.
9
*/
10
package eu.etaxonomy.cdm.model.common;
11

  
12
import java.util.Comparator;
13

  
14
/**
15
 * @author a.mueller
16
 * @date 05.07.2016
17
 *
18
 * Comparator for tree indexes.
19
 * Compares the tree indexes node by node, sorted by node number.
20
 * If one index is shorter than the other one but
21
 */
22
public class TreeIndexComparator implements Comparator<TreeIndex>{
23

  
24
    @Override
25
    public int compare(TreeIndex treeIndex1, TreeIndex treeIndex2) {
26
        if (treeIndex1 == null && treeIndex2 == null){
27
            return 0;
28
        }else if (treeIndex1 == null){
29
            return -1;
30
        }else if (treeIndex2 == null){
31
            return 1;
32
        }
33
        if (treeIndex1.equals(treeIndex2)){
34
            return 0;
35
        }
36

  
37
        String[] splits1 = treeIndex1.toString().split(ITreeNode.separator);
38
        String[] splits2 = treeIndex2.toString().split(ITreeNode.separator);
39

  
40

  
41
        for (int i=0; i < splits1.length; i++){
42
            if (splits2.length <= i){
43
                return 1;
44
            }
45
            int c = splits1[i].compareTo(splits2[i]);
46
            if (c != 0){
47
                return c;
48
            }
49
        }
50
        return -1;
51

  
52
    }
53

  
54
}
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/hibernate/taxon/ClassificationDaoHibernateImpl.java
12 12

  
13 13
import java.util.ArrayList;
14 14
import java.util.HashMap;
15
import java.util.HashSet;
15 16
import java.util.List;
16 17
import java.util.Map;
18
import java.util.Set;
17 19
import java.util.UUID;
18 20

  
19 21
import org.apache.log4j.Logger;
......
22 24
import org.springframework.beans.factory.annotation.Qualifier;
23 25
import org.springframework.stereotype.Repository;
24 26

  
27
import eu.etaxonomy.cdm.model.common.MarkerType;
28
import eu.etaxonomy.cdm.model.common.TreeIndex;
25 29
import eu.etaxonomy.cdm.model.name.Rank;
26 30
import eu.etaxonomy.cdm.model.taxon.Classification;
27 31
import eu.etaxonomy.cdm.model.taxon.Taxon;
......
252 256

  
253 257
    @Override
254 258
    public UUID delete(Classification persistentObject){
255
        //delete all childnodes, then delete the tree
259
        //delete all child nodes, then delete the tree
256 260

  
257 261
        List<TaxonNode> nodes = persistentObject.getChildNodes();
258 262
        List<TaxonNode> nodesTmp = new ArrayList<TaxonNode>(nodes);
......
299 303
    }
300 304

  
301 305
    @Override
302
    public Map<UUID, String> treeIndexForTaxonUuids(UUID classificationUuid,
306
    public Map<UUID, TreeIndex> treeIndexForTaxonUuids(UUID classificationUuid,
303 307
            List<UUID> taxonUuids) {
304 308
        String hql = " SELECT t.uuid, tn.treeIndex "
305 309
                + " FROM Taxon t JOIN t.taxonNodes tn "
......
311 315
        query.setParameter("classificationUuid", classificationUuid);
312 316
        query.setParameterList("taxonUuids", taxonUuids);
313 317

  
314
        Map<UUID, String> result = new HashMap<>();
318
        Map<UUID, TreeIndex> result = new HashMap<>();
315 319
        @SuppressWarnings("unchecked")
316 320
        List<Object[]> list = query.list();
317 321
        for (Object[] o : list){
318
            result.put((UUID)o[0], (String)o[1]);
322
            result.put((UUID)o[0], TreeIndex.NewInstance((String)o[1]));
319 323
        }
320 324
        return result;
321 325
    }
322 326

  
327
    @Override
328
    public Set<TreeIndex> getMarkedTreeIndexes(MarkerType markerType, Boolean flag){
329
        String hql = " SELECT tn.treeIndex "
330
                + " FROM Taxon t JOIN t.taxonNodes tn "
331
                + "     JOIN t.markers m "
332
                + " WHERE (1=1)"
333
                + "   AND m.markerType = :markerType "
334
                ;
335
        if (flag != null){
336
            hql += "  AND m.flag = :flag ";
337

  
338
        }
339

  
340
        Query query =  getSession().createQuery(hql);
341
        if (flag != null){
342
            query.setParameter("flag", flag);
343
        }
344
        query.setParameter("markerType", markerType);
345

  
346
        Set<TreeIndex> result = new HashSet<>();
347
        @SuppressWarnings("unchecked")
348
        List<String> list = query.list();
349
        for (String o : list){
350
            result.add(TreeIndex.NewInstance(o));
351
        }
352
        return result;
353
    }
323 354

  
324
    /**
325
     * {@inheritDoc}
326
     */
327 355
    @Override
328 356
    public Map<UUID, UUID> getTaxonNodeUuidByTaxonUuid(UUID classificationUuid, List<UUID> taxonUuids) {
329 357
        String hql = " SELECT t.uuid, tn.uuid "
......
345 373
        return result;
346 374
    }
347 375

  
348

  
349

  
350 376
}
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/hibernate/taxon/TaxonNodeDaoHibernateImpl.java
12 12

  
13 13
import java.math.BigInteger;
14 14
import java.util.ArrayList;
15
import java.util.Collection;
15 16
import java.util.HashMap;
16 17
import java.util.Iterator;
17 18
import java.util.List;
......
30 31
import org.springframework.stereotype.Repository;
31 32

  
32 33
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
34
import eu.etaxonomy.cdm.model.common.TreeIndex;
33 35
import eu.etaxonomy.cdm.model.taxon.Classification;
34 36
import eu.etaxonomy.cdm.model.taxon.Taxon;
35 37
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
......
119 121
        List<TaxonNode> result  = getSession().createSQLQuery(queryString).addEntity(TaxonNode.class).list();
120 122

  
121 123
       return result;
122

  
123

  
124 124
	}
125 125

  
126 126
    @Override
......
157 157
        	queryString += "AND cls.uuid = :classificationUuid";
158 158
        }
159 159
        Query query =  getSession().createQuery(queryString);
160
        
160

  
161 161
        query.setParameter("pattern", pattern.toLowerCase()+"%");
162 162
        query.setParameter("classificationUuid", classificationUuid);
163
        
163

  
164 164
        List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>();
165 165

  
166 166
        List<Object[]> result = query.list();
......
378 378
    }
379 379

  
380 380
    @Override
381
    public Map<String, Integer> rankOrderIndexForTreeIndex(List<String> treeIndexes,
381
    public Map<TreeIndex, Integer> rankOrderIndexForTreeIndex(List<TreeIndex> treeIndexes,
382 382
            Integer minRankOrderIndex,
383 383
            Integer maxRankOrderIndex) {
384 384

  
385
        Map<String, Integer> result = new HashMap<>();
385
        Map<TreeIndex, Integer> result = new HashMap<>();
386 386
        if (treeIndexes == null || treeIndexes.isEmpty()){
387 387
            return result;
388 388
        }
......
398 398
        }
399 399

  
400 400
        Query query =  getSession().createQuery(hql);
401
        query.setParameterList("treeIndexes", treeIndexes);
401
        query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));
402 402
        if (minRankOrderIndex != null){
403 403
            query.setParameter("minOrderIndex", minRankOrderIndex);
404 404
        }
......
409 409
        @SuppressWarnings("unchecked")
410 410
        List<Object[]> list = query.list();
411 411
        for (Object[] o : list){
412
            result.put((String)o[0], (Integer)o[1]);
412
            result.put(TreeIndex.NewInstance((String)o[0]), (Integer)o[1]);
413 413
        }
414 414
        return result;
415 415
    }
416 416

  
417 417
    @Override
418
    public Map<String, UuidAndTitleCache<?>> taxonUuidsForTreeIndexes(Set<String> treeIndexes) {
419
        Map<String, UuidAndTitleCache<?>> result = new HashMap<>();
418
    public Map<TreeIndex, UuidAndTitleCache<?>> taxonUuidsForTreeIndexes(Collection<TreeIndex> treeIndexes) {
419
        Map<TreeIndex, UuidAndTitleCache<?>> result = new HashMap<>();
420 420
        if (treeIndexes == null || treeIndexes.isEmpty()){
421 421
            return result;
422 422
        }
......
425 425
                + " FROM TaxonNode tn JOIN tn.taxon t Join t.name tnb "
426 426
                + " WHERE tn.treeIndex IN (:treeIndexes) ";
427 427
        Query query =  getSession().createQuery(hql);
428
        query.setParameterList("treeIndexes", treeIndexes);
428
        query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));
429 429

  
430 430
        @SuppressWarnings("unchecked")
431 431
        List<Object[]> list = query.list();
432 432
        for (Object[] o : list){
433
            result.put((String)o[0], new UuidAndTitleCache<>((UUID)o[1], null, (String)o[2]));
433
            result.put(TreeIndex.NewInstance((String)o[0]), new UuidAndTitleCache<>((UUID)o[1], null, (String)o[2]));
434 434
        }
435 435
        return result;
436 436
    }
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/taxon/IClassificationDao.java
11 11

  
12 12
import java.util.List;
13 13
import java.util.Map;
14
import java.util.Set;
14 15
import java.util.UUID;
15 16

  
17
import eu.etaxonomy.cdm.model.common.MarkerType;
18
import eu.etaxonomy.cdm.model.common.TreeIndex;
16 19
import eu.etaxonomy.cdm.model.name.Rank;
17 20
import eu.etaxonomy.cdm.model.taxon.Classification;
18 21
import eu.etaxonomy.cdm.model.taxon.Taxon;
......
79 82
     * @param propertyPaths
80 83
     * @return
81 84
     */
82
    List<TaxonNode> listSiblingsOf(Taxon taxon, Classification classification, Integer pageSize, Integer pageIndex,
85
    public List<TaxonNode> listSiblingsOf(Taxon taxon, Classification classification, Integer pageSize, Integer pageIndex,
83 86
            List<String> propertyPaths);
84 87

  
85 88
    /**
......
87 90
     * @param classification
88 91
     * @return
89 92
     */
90
    Long countSiblingsOf(Taxon taxon, Classification classification);
93
    public Long countSiblingsOf(Taxon taxon, Classification classification);
91 94

  
92 95
    /**
93 96
     * Returns the tree indexes for a given set of taxon uuids as a map.
......
95 98
     * @param originalTaxonUuids
96 99
     * @return
97 100
     */
98
    Map<UUID, String> treeIndexForTaxonUuids( UUID classificationUuid, List<UUID> originalTaxonUuids);
101
    public Map<UUID, TreeIndex> treeIndexForTaxonUuids( UUID classificationUuid, List<UUID> originalTaxonUuids);
102

  
103
    /**
104
     * @param markerType
105
     * @param value
106
     * @return
107
     */
108
    public Set<TreeIndex> getMarkedTreeIndexes(MarkerType markerType, Boolean value);
99 109

  
100 110
    /**
101 111
     * Returns a map of taxon uuids mapping to taxon node uuids in the given classification
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/taxon/ITaxonNodeDao.java
9 9

  
10 10
package eu.etaxonomy.cdm.persistence.dao.taxon;
11 11

  
12
import java.util.Collection;
12 13
import java.util.List;
13 14
import java.util.Map;
14
import java.util.Set;
15 15
import java.util.UUID;
16 16

  
17
import eu.etaxonomy.cdm.model.common.TreeIndex;
17 18
import eu.etaxonomy.cdm.model.taxon.Classification;
18 19
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
19 20
import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
......
109 110
     * @param maxRankOrderIndex max rank
110 111
     * @return
111 112
     */
112
    Map<String, Integer> rankOrderIndexForTreeIndex(List<String> treeIndex, Integer minRankOrderIndex,
113
    Map<TreeIndex, Integer> rankOrderIndexForTreeIndex(List<TreeIndex> treeIndex, Integer minRankOrderIndex,
113 114
            Integer maxRankOrderIndex);
114 115

  
115 116
    /**
......
118 119
     * @param treeIndexSet set of taxon node tree indexes
119 120
     * @return map with treeindex and uuidAndTitleCache of the represented taxon
120 121
     */
121
    Map<String, UuidAndTitleCache<?>> taxonUuidsForTreeIndexes(Set<String> treeIndexSet);
122
    Map<TreeIndex, UuidAndTitleCache<?>> taxonUuidsForTreeIndexes(Collection<TreeIndex> treeIndexSet);
122 123

  
123 124
}
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/ClassificationController.java
35 35
import eu.etaxonomy.cdm.api.service.dto.TaxonInContextDTO;
36 36
import eu.etaxonomy.cdm.api.service.pager.Pager;
37 37
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
38
import eu.etaxonomy.cdm.model.common.MarkerType;
38 39
import eu.etaxonomy.cdm.model.name.Rank;
39 40
import eu.etaxonomy.cdm.model.taxon.Classification;
40 41
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
......
189 190
            @RequestParam(value = "taxonUuids", required = true) UuidList taxonUuids,
190 191
            @RequestParam(value = "minRankUuid", required = false) UUID minRankUuid,
191 192
            @RequestParam(value = "maxRankUuid", required = false) UUID maxRankUuid,
193

  
192 194
            HttpServletRequest request,
193 195
            HttpServletResponse response
194 196
            ) throws IOException {
......
201 203
            return null;
202 204
        }
203 205

  
204

  
205 206
        Rank minRank = findRank(minRankUuid);
206 207
        Rank maxRank = findRank(maxRankUuid);
207 208

  
......
212 213
        return result;
213 214
    }
214 215

  
216
    /**
217
     * @param classificationUuid
218
     * @param response
219
     * @return
220
     * @throws IOException
221
     */
222
    @RequestMapping(
223
            value = {"groupedTaxaByMarker"},
224
            method = RequestMethod.GET)
225
    public List<GroupedTaxonDTO> getGroupedTaxaByMarkedParents(
226
            @PathVariable("uuid") UUID classificationUuid,
227
            @RequestParam(value = "taxonUuids", required = true) UuidList taxonUuids,
228
            @RequestParam(value = "markerTypeUuid", required = false) UUID markerTypeUuid,
229
            @RequestParam(value = "flag", required = false) Boolean flag,
230

  
231
            HttpServletRequest request,
232
            HttpServletResponse response
233
            ) throws IOException {
234

  
235
        logger.info("getGroupedTaxaByHigherTaxon() - " + request.getRequestURI());
236

  
237
        Classification classification = service.find(classificationUuid);
238
        if(classification == null) {
239
            response.sendError(404 , "Classification not found using " + classificationUuid );
240
            return null;
241
        }
242

  
243
        MarkerType markerType = findMarkerType(markerTypeUuid);
244
//        long start = System.currentTimeMillis();
245
        List<GroupedTaxonDTO> result = service.groupTaxaByMarkedParents(taxonUuids, classificationUuid, markerType, flag);
246
//        System.err.println("service.listRankSpecificRootNodes() " + (System.currentTimeMillis() - start));
247

  
248
        return result;
249
    }
250

  
215 251

  
216 252
    private Rank findRank(UUID rankUuid) {
217 253
        Rank rank = null;
......
226 262
        return rank;
227 263
    }
228 264

  
265
    private MarkerType findMarkerType(UUID markerTypeUuid) {
266
        MarkerType markerType = null;
267
        if(markerTypeUuid != null){
268
            DefinedTermBase<?> definedTermBase =  termService.find(markerTypeUuid);
269
            if(definedTermBase instanceof MarkerType){
270
                markerType = (MarkerType) definedTermBase;
271
            } else {
272
               throw new IllegalArgumentException("DefinedTermBase is not a MarkerType");
273
            }
274
        }
275
        return markerType;
276
    }
277

  
229 278

  
230 279
   @RequestMapping(
231 280
           value = {"taxonInContext/{taxonUuid}"},
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ClassificationServiceImpl.java
16 16
import java.util.Collections;
17 17
import java.util.Comparator;
18 18
import java.util.HashMap;
19
import java.util.HashSet;
19 20
import java.util.List;
20 21
import java.util.Map;
22
import java.util.Set;
21 23
import java.util.TreeMap;
22 24
import java.util.UUID;
23 25

  
......
47 49
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
48 50
import eu.etaxonomy.cdm.model.common.ITreeNode;
49 51
import eu.etaxonomy.cdm.model.common.MarkerType;
52
import eu.etaxonomy.cdm.model.common.TreeIndex;
50 53
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
51 54
import eu.etaxonomy.cdm.model.description.TaxonDescription;
52 55
import eu.etaxonomy.cdm.model.media.Media;
......
700 703
        List<GroupedTaxonDTO> result = new ArrayList<>();
701 704

  
702 705
        //get treeindex for each taxonUUID
703
        Map<UUID, String> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
706
        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
704 707

  
705 708
        //build treeindex list (or tree)
706
        List<String> treeIndexClosure = new ArrayList<>();
707
        for (String treeIndex : taxonIdTreeIndexMap.values()){
708
            String[] splits = treeIndex.substring(1).split(ITreeNode.separator);
709
        //TODO make it work with TreeIndex or move there
710
        List<String> treeIndexClosureStr = new ArrayList<>();
711
        for (TreeIndex treeIndex : taxonIdTreeIndexMap.values()){
712
            String[] splits = treeIndex.toString().substring(1).split(ITreeNode.separator);
709 713
            String currentIndex = ITreeNode.separator;
710 714
            for (String split : splits){
711 715
                if (split.equals("")){
712 716
                    continue;
713 717
                }
714 718
                currentIndex += split + ITreeNode.separator;
715
                if (!treeIndexClosure.contains(currentIndex) && !split.startsWith(ITreeNode.treePrefix)){
716
                    treeIndexClosure.add(currentIndex);
719
                if (!treeIndexClosureStr.contains(currentIndex) && !split.startsWith(ITreeNode.treePrefix)){
720
                    treeIndexClosureStr.add(currentIndex);
717 721
                }
718 722
            }
719 723
        }
......
721 725
        //get rank sortindex for all parent taxa with sortindex <= minRank and sortIndex >= maxRank (if available)
722 726
        Integer minRankOrderIndex = minRank == null ? null : minRank.getOrderIndex();
723 727
        Integer maxRankOrderIndex = maxRank == null ? null : maxRank.getOrderIndex();
724
        Map<String, Integer> treeIndexSortIndexMapTmp = taxonNodeDao.rankOrderIndexForTreeIndex(treeIndexClosure, minRankOrderIndex, maxRankOrderIndex);
728
        List<TreeIndex> treeIndexClosure = TreeIndex.NewListInstance(treeIndexClosureStr);
729

  
730
        Map<TreeIndex, Integer> treeIndexSortIndexMapTmp = taxonNodeDao.rankOrderIndexForTreeIndex(treeIndexClosure, minRankOrderIndex, maxRankOrderIndex);
725 731

  
726 732
        //remove all treeindex with "exists child in above map(and child.sortindex > xxx)
727
        List<String> treeIndexList = new ArrayList<>(treeIndexSortIndexMapTmp.keySet());
728
        Collections.sort(treeIndexList, new TreeIndexComparator());
729
        Map<String, Integer> treeIndexSortIndexMap = new HashMap<>();
730
        String lastTreeIndex = null;
731
        for (String treeIndex : treeIndexList){
732
            if (lastTreeIndex != null && treeIndex.startsWith(lastTreeIndex)){
733
        List<TreeIndex> treeIndexList = TreeIndex.sort(treeIndexSortIndexMapTmp.keySet());
734

  
735
        Map<TreeIndex, Integer> treeIndexSortIndexMap = new HashMap<>();
736
        TreeIndex lastTreeIndex = null;
737
        for (TreeIndex treeIndex : treeIndexList){
738
            if (lastTreeIndex != null && lastTreeIndex.hasChild(treeIndex)){
733 739
                treeIndexSortIndexMap.remove(lastTreeIndex);
734 740
            }
735 741
            treeIndexSortIndexMap.put(treeIndex, treeIndexSortIndexMapTmp.get(treeIndex));
......
737 743
        }
738 744

  
739 745
        //get taxonID for treeIndexes
740
        Map<String, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(treeIndexSortIndexMap.keySet());
746
        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(treeIndexSortIndexMap.keySet());
741 747

  
742 748
        //fill result list
743 749
        for (UUID originalTaxonUuid : originalTaxonUuids){
744 750
            GroupedTaxonDTO item = new GroupedTaxonDTO();
745 751
            result.add(item);
746 752
            item.setTaxonUuid(originalTaxonUuid);
747
            String groupIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
748
            while (groupIndex != null){
749
                if (treeIndexTaxonIdMap.get(groupIndex) != null){
750
                    UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupIndex);
753
            TreeIndex groupTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
754
            String groupIndexX = TreeIndex.toString(groupTreeIndex);
755
            while (groupTreeIndex != null){
756
                if (treeIndexTaxonIdMap.get(groupTreeIndex) != null){
757
                    UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
751 758
                    item.setGroupTaxonUuid(uuidAndLabel.getUuid());
752 759
                    item.setGroupTaxonName(uuidAndLabel.getTitleCache());
753 760
                    break;
754 761
                }else{
755
                    int index = groupIndex.substring(0, groupIndex.length()-1).lastIndexOf(ITreeNode.separator);
756
                    groupIndex = index<0 ? null : groupIndex.substring(0, index+1);
762
                    groupTreeIndex = groupTreeIndex.parent();
763
//                    int index = groupIndex.substring(0, groupIndex.length()-1).lastIndexOf(ITreeNode.separator);
764
//                    groupIndex = index < 0 ? null : groupIndex.substring(0, index+1);
757 765
                }
758 766
            }
759 767
        }
......
765 773
     * {@inheritDoc}
766 774
     */
767 775
    @Override
776
    public List<GroupedTaxonDTO> groupTaxaByMarkedParents(List<UUID> originalTaxonUuids, UUID classificationUuid,
777
            MarkerType markerType, Boolean flag) {
778

  
779
        List<GroupedTaxonDTO> result = new ArrayList<>();
780

  
781
        //get treeindex for each taxonUUID
782
        Map<UUID, TreeIndex> taxonIdTreeIndexMap = dao.treeIndexForTaxonUuids(classificationUuid, originalTaxonUuids);
783

  
784
        //get all marked tree indexes
785
        Set<TreeIndex> markedTreeIndexes = dao.getMarkedTreeIndexes(markerType, flag);
786

  
787

  
788
        Map<TreeIndex, TreeIndex> groupedMap = TreeIndex.group(markedTreeIndexes, taxonIdTreeIndexMap.values());
789
        Set<TreeIndex> notNullGroups = new HashSet<>(groupedMap.values());
790
        notNullGroups.remove(null);
791

  
792
        //get taxonInfo for treeIndexes
793
        Map<TreeIndex, UuidAndTitleCache<?>> treeIndexTaxonIdMap = taxonNodeDao.taxonUuidsForTreeIndexes(notNullGroups);
794

  
795
        //fill result list
796
        for (UUID originalTaxonUuid : originalTaxonUuids){
797
            GroupedTaxonDTO item = new GroupedTaxonDTO();
798
            result.add(item);
799
            item.setTaxonUuid(originalTaxonUuid);
800

  
801
            TreeIndex toBeGroupedTreeIndex = taxonIdTreeIndexMap.get(originalTaxonUuid);
802
            TreeIndex groupTreeIndex = groupedMap.get(toBeGroupedTreeIndex);
803
            UuidAndTitleCache<?> uuidAndLabel = treeIndexTaxonIdMap.get(groupTreeIndex);
804
            if (uuidAndLabel != null){
805
                item.setGroupTaxonUuid(uuidAndLabel.getUuid());
806
                item.setGroupTaxonName(uuidAndLabel.getTitleCache());
807
            }
808
        }
809

  
810
        return result;
811
    }
812

  
813
    /**
814
     * {@inheritDoc}
815
     */
816
    @Override
768 817
    public UUID getTaxonNodeUuidByTaxonUuid(UUID classificationUuid, UUID taxonUuid) {
769 818
        Map<UUID, UUID> map = dao.getTaxonNodeUuidByTaxonUuid(classificationUuid, Arrays.asList(taxonUuid));
770 819
        UUID taxonNodeUuid = map.get(taxonUuid);
......
938 987
        }
939 988
    }
940 989

  
990

  
941 991
}
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/IClassificationService.java
20 20
import eu.etaxonomy.cdm.api.service.dto.GroupedTaxonDTO;
21 21
import eu.etaxonomy.cdm.api.service.dto.TaxonInContextDTO;
22 22
import eu.etaxonomy.cdm.api.service.pager.Pager;
23
import eu.etaxonomy.cdm.model.common.MarkerType;
23 24
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
24 25
import eu.etaxonomy.cdm.model.name.Rank;
25 26
import eu.etaxonomy.cdm.model.reference.Reference;
......
349 350
    List<GroupedTaxonDTO> groupTaxaByHigherTaxon(List<UUID> taxonUuids, UUID classificationUuid, Rank minRank, Rank maxRank);
350 351

  
351 352
    /**
353
     * @param taxonUuids
354
     * @param classificationUuid
355
     * @param markerType
356
     * @param value
357
     * @return
358
     */
359
    public List<GroupedTaxonDTO> groupTaxaByMarkedParents(List<UUID> taxonUuids, UUID classificationUuid,
360
            MarkerType markerType, Boolean value);
361

  
362

  
363
    /**
352 364
     * Returns the most relevant data of a taxon/taxon node, including children, synonyms
353 365
     * and certain ancestors if required.
354 366
     * @param classificationUuid
......
365 377
     * @param classification
366 378
     * @return
367 379
     */
368
    UUID saveClassification(Classification classification);
380
    public UUID saveClassification(Classification classification);
381

  
369 382

  
370 383

  
371 384
}
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TreeIndexComparator.java
1
// $Id$
2
/**
3
* Copyright (C) 2016 EDIT
4
* European Distributed Institute of Taxonomy
5
* http://www.e-taxonomy.eu
6
*
7
* The contents of this file are subject to the Mozilla Public License Version 1.1
8
* See LICENSE.TXT at the top of this package for the full license terms.
9
*/
10
package eu.etaxonomy.cdm.api.service;
11

  
12
import java.util.Comparator;
13

  
14
import eu.etaxonomy.cdm.model.common.ITreeNode;
15

  
16
/**
17
 * @author a.mueller
18
 * @date 05.07.2016
19
 *
20
 * Comparator for treeindexes.
21
 * Compares the tree indexes node by node, sorted by node number.
22
 * If one index is shorter than the other one but
23
 */
24
public class TreeIndexComparator implements Comparator<String>{
25

  
26
    @Override
27
    public int compare(String treeIndex1, String treeIndex2) {
28
        if (treeIndex1 == null && treeIndex2 == null){
29
            return 0;
30
        }else if (treeIndex1 == null){
31
            return -1;
32
        }else if (treeIndex2 == null){
33
            return 1;
34
        }
35
        if (treeIndex1.equals(treeIndex2)){
36
            return 0;
37
        }
38

  
39
        String[] splits1 = treeIndex1.split(ITreeNode.separator);
40
        String[] splits2 = treeIndex2.split(ITreeNode.separator);
41

  
42

  
43
        for (int i=0; i < splits1.length; i++){
44
            if (splits2.length <= i){
45
                return 1;
46
            }
47
            int c = splits1[i].compareTo(splits2[i]);
48
            if (c != 0){
49
                return c;
50
            }
51
        }
52
        return -1;
53

  
54
    }
55

  
56

  
57
}
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/TreeIndexComparatorTest.java
12 12
import org.junit.Assert;
13 13
import org.junit.Test;
14 14

  
15
import eu.etaxonomy.cdm.model.common.TreeIndex;
16
import eu.etaxonomy.cdm.model.common.TreeIndexComparator;
17

  
15 18

  
16 19
/**
17 20
 * @author a.mueller
......
24 27
    public void test() {
25 28
        TreeIndexComparator comparator = new TreeIndexComparator();
26 29

  
30
        TreeIndex ti10 = TreeIndex.NewInstance("#t10#10#");
31
        TreeIndex ti10_20 = TreeIndex.NewInstance("#t10#10#20#");
32
        TreeIndex ti10_30 = TreeIndex.NewInstance("#t10#10#30#");
33
        TreeIndex ti10_30_11 = TreeIndex.NewInstance("#t10#10#30#11#");
34

  
27 35
        //both null
28 36
        Assert.assertTrue(0 == comparator.compare(null, null));
29 37
        //one null
30
        Assert.assertTrue(0 > comparator.compare(null, "#t10#10#"));
31
        Assert.assertTrue(0 < comparator.compare("#t10#10#", null));
38
        Assert.assertTrue(0 > comparator.compare(null, ti10));
39
        Assert.assertTrue(0 < comparator.compare(ti10, null));
32 40
        //equal
33
        Assert.assertTrue(0 == comparator.compare("#t10#10#", "#t10#10#"));
41
        Assert.assertTrue(0 == comparator.compare(ti10, ti10));
34 42

  
35 43
        //same start
36
        Assert.assertTrue(0 > comparator.compare("#t10#10#", "#t10#10#20#"));
37
        Assert.assertTrue(0 < comparator.compare("#t10#10#20#", "#t10#10#"));
44
        Assert.assertTrue(0 > comparator.compare(ti10, ti10_20));
45
        Assert.assertTrue(0 < comparator.compare(ti10_20, ti10));
38 46

  
39 47
        //different ends
40
        Assert.assertTrue(0 > comparator.compare("#t10#10#20#", "#t10#10#30#"));
41
        Assert.assertTrue(0 < comparator.compare("#t10#10#30#", "#t10#10#20#"));
48
        Assert.assertTrue(0 > comparator.compare(ti10_20, ti10_30));
49
        Assert.assertTrue(0 < comparator.compare(ti10_30, ti10_20));
42 50

  
43 51
        //different ends
44
        Assert.assertTrue(0 > comparator.compare("#t10#10#20#", "#t10#10#30#"));
45
        Assert.assertTrue(0 > comparator.compare("#t10#10#20#", "#t10#10#30#11"));
52
        Assert.assertTrue(0 > comparator.compare(ti10_20, ti10_30));
53
        Assert.assertTrue(0 > comparator.compare(ti10_20, ti10_30_11));
46 54

  
47
        Assert.assertTrue(0 < comparator.compare("#t10#10#30#", "#t10#10#20#"));
48
        Assert.assertTrue(0 < comparator.compare("#t10#10#30#11", "#t10#10#20#"));
55
        Assert.assertTrue(0 < comparator.compare(ti10_30, ti10_20));
56
        Assert.assertTrue(0 < comparator.compare(ti10_30_11, ti10_20));
49 57

  
50 58
    }
51 59

  

Also available in: Unified diff

Add picture from clipboard (Maximum size: 40 MB)