Revision 45cac117
Added by Katja Luther over 5 years ago
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/common/OrderIndexComparator.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2018 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.Comparator; |
|
12 |
|
|
13 |
/** |
|
14 |
* @author k.luther |
|
15 |
* @since 07.12.2018 |
|
16 |
* |
|
17 |
*/ |
|
18 |
public class OrderIndexComparator implements Comparator<Integer> { |
|
19 |
|
|
20 |
private static OrderIndexComparator instance; |
|
21 |
|
|
22 |
|
|
23 |
|
|
24 |
public static OrderIndexComparator instance(){ |
|
25 |
if(instance == null){ |
|
26 |
instance = new OrderIndexComparator(); |
|
27 |
} |
|
28 |
return instance; |
|
29 |
} |
|
30 |
|
|
31 |
/** |
|
32 |
* {@inheritDoc} |
|
33 |
*/ |
|
34 |
@Override |
|
35 |
public int compare(Integer orderIndex1, Integer orderIndex2) { |
|
36 |
if (orderIndex1 == orderIndex2){ |
|
37 |
return 0; |
|
38 |
} |
|
39 |
if (orderIndex1 == null){ |
|
40 |
return 1; |
|
41 |
} |
|
42 |
if (orderIndex2 == null){ |
|
43 |
return -1; |
|
44 |
} |
|
45 |
if (orderIndex1<orderIndex2){ |
|
46 |
return -1; |
|
47 |
}else{ |
|
48 |
return 1; |
|
49 |
} |
|
50 |
|
|
51 |
} |
|
52 |
|
|
53 |
} |
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dto/TaxonNodeDto.java | ||
---|---|---|
12 | 12 |
import java.util.List; |
13 | 13 |
import java.util.UUID; |
14 | 14 |
|
15 |
import eu.etaxonomy.cdm.model.name.Rank; |
|
16 | 15 |
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode; |
17 | 16 |
import eu.etaxonomy.cdm.model.taxon.Synonym; |
18 | 17 |
import eu.etaxonomy.cdm.model.taxon.Taxon; |
... | ... | |
75 | 74 |
|
76 | 75 |
private final String treeIndex; |
77 | 76 |
private final Integer sortIndex; |
78 |
private Rank rank; |
|
77 |
|
|
78 |
private Integer rankOrderIndex; |
|
79 | 79 |
|
80 | 80 |
|
81 | 81 |
|
... | ... | |
96 | 96 |
taggedTitle = taxon.getName() != null? taxon.getName().getTaggedName() : taxon.getTaggedTitle(); |
97 | 97 |
rankLabel = taxon.getNullSafeRank() != null ? taxon.getNullSafeRank().getLabel() : null; |
98 | 98 |
this.setAbbrevTitleCache(taxon.getTitleCache()); |
99 |
rank = taxon.getName() != null? taxon.getName().getRank() : null; |
|
99 |
rankOrderIndex = taxon.getName() != null && taxon.getName().getRank() != null? taxon.getName().getRank().getOrderIndex() : null; |
|
100 |
|
|
100 | 101 |
}else{ |
101 | 102 |
setTitleCache(taxonNode.getClassification().getTitleCache()); |
102 |
rank = null; |
|
103 |
rankOrderIndex = null;
|
|
103 | 104 |
} |
104 | 105 |
taxonomicChildrenCount = taxonNode.getCountChildren(); |
105 | 106 |
unplaced = taxonNode.isUnplaced(); |
... | ... | |
208 | 209 |
return sortIndex; |
209 | 210 |
} |
210 | 211 |
|
211 |
public Rank getRank() {
|
|
212 |
return rank; |
|
212 |
public Integer getRankOrderIndex() {
|
|
213 |
return rankOrderIndex;
|
|
213 | 214 |
} |
214 | 215 |
|
215 |
public void setRank(Rank rank) { |
|
216 |
this.rank = rank; |
|
217 |
} |
|
218 | 216 |
|
219 | 217 |
public String getTaxonTitleCache(){ |
220 | 218 |
return getAbbrevTitleCache(); |
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/NodeDtoSortMode.java | ||
---|---|---|
3 | 3 |
import java.util.Comparator; |
4 | 4 |
|
5 | 5 |
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto; |
6 |
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDtoByNameComparator; |
|
7 |
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDtoByRankAndNameComparator; |
|
8 |
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDtoNaturalComparator; |
|
6 | 9 |
|
7 | 10 |
public enum NodeDtoSortMode { |
8 | 11 |
|
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonNodeDtoByNameComparator.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2018 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.api.service; |
|
10 |
|
|
11 |
import java.util.Comparator; |
|
12 |
import java.util.StringTokenizer; |
|
13 |
|
|
14 |
import org.apache.log4j.Logger; |
|
15 |
|
|
16 |
import eu.etaxonomy.cdm.common.AbstractStringComparator; |
|
17 |
import eu.etaxonomy.cdm.common.UTF8; |
|
18 |
import eu.etaxonomy.cdm.model.taxon.ITaxonNodeComparator; |
|
19 |
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByNameComparator; |
|
20 |
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto; |
|
21 |
|
|
22 |
/** |
|
23 |
* @author k.luther/a.kohlbecker |
|
24 |
* @since 09.03.2018 |
|
25 |
* |
|
26 |
*/ |
|
27 |
public class TaxonNodeDtoByNameComparator extends AbstractStringComparator<TaxonNodeDto> implements Comparator<TaxonNodeDto>, ITaxonNodeComparator<TaxonNodeDto>{ |
|
28 |
|
|
29 |
private static final String HYBRID_SIGN = UTF8.HYBRID.toString(); |
|
30 |
|
|
31 |
private static final Logger logger = Logger.getLogger(TaxonNodeByNameComparator.class); |
|
32 |
|
|
33 |
private boolean ignoreHybridSign = true; |
|
34 |
private boolean sortInfraGenericFirst = true; |
|
35 |
|
|
36 |
@Override |
|
37 |
public int compare(TaxonNodeDto node1, TaxonNodeDto node2) { |
|
38 |
if (node1 == null && node2 == null) { |
|
39 |
return 0; |
|
40 |
} |
|
41 |
else if (node1 == null) { |
|
42 |
return 1; |
|
43 |
} |
|
44 |
else if (node2 == null) { |
|
45 |
return -1; |
|
46 |
} |
|
47 |
if (node1.equals(node2)){ |
|
48 |
return 0; |
|
49 |
} |
|
50 |
boolean node1Excluded = node1.isExcluded(); |
|
51 |
boolean node2Excluded = node2.isExcluded(); |
|
52 |
boolean node1Unplaced = node1.isUnplaced(); |
|
53 |
boolean node2Unplaced = node2.isUnplaced(); |
|
54 |
|
|
55 |
//They should both be put to the end (first unplaced then excluded) |
|
56 |
if (node2Excluded && !node1Excluded){ |
|
57 |
return -1; |
|
58 |
} |
|
59 |
if (node2Unplaced && !(node1Unplaced || node1Excluded)){ |
|
60 |
return -1; |
|
61 |
} |
|
62 |
|
|
63 |
if (node1Excluded && !node2Excluded){ |
|
64 |
return 1; |
|
65 |
} |
|
66 |
if (node1Unplaced && !(node2Unplaced || node2Excluded)){ |
|
67 |
return 1; |
|
68 |
} |
|
69 |
|
|
70 |
if (node1Unplaced && node2Excluded){ |
|
71 |
return -1; |
|
72 |
} |
|
73 |
if (node2Unplaced && node1Excluded){ |
|
74 |
return 1; |
|
75 |
} |
|
76 |
|
|
77 |
String titleCache1 = createSortableTitleCache(node1); |
|
78 |
String titleCache2 = createSortableTitleCache(node2); |
|
79 |
|
|
80 |
if(isIgnoreHybridSign()) { |
|
81 |
if (logger.isTraceEnabled()){logger.trace("ignoring Hybrid Signs: " + HYBRID_SIGN);} |
|
82 |
titleCache1 = titleCache1.replace(HYBRID_SIGN, ""); |
|
83 |
titleCache2 = titleCache2.replace(HYBRID_SIGN, ""); |
|
84 |
} |
|
85 |
|
|
86 |
titleCache1 = applySubstitutionRules(titleCache1); |
|
87 |
titleCache2 = applySubstitutionRules(titleCache2); |
|
88 |
|
|
89 |
// 1 |
|
90 |
StringTokenizer s2 = new StringTokenizer(titleCache1, "\""); |
|
91 |
if (s2.countTokens()>0){ |
|
92 |
titleCache1 = ""; |
|
93 |
} |
|
94 |
while(s2.hasMoreTokens()){ |
|
95 |
titleCache1 += s2.nextToken(); |
|
96 |
} |
|
97 |
|
|
98 |
// 2 |
|
99 |
s2 = new StringTokenizer(titleCache2, "\""); |
|
100 |
if (s2.countTokens()>0){ |
|
101 |
titleCache2 = ""; |
|
102 |
} |
|
103 |
|
|
104 |
while(s2.hasMoreTokens()){ |
|
105 |
titleCache2 += s2.nextToken(); |
|
106 |
} |
|
107 |
|
|
108 |
int result = titleCache1.compareTo(titleCache2); |
|
109 |
if (result != 0){ |
|
110 |
return result; |
|
111 |
}else{ |
|
112 |
return node1.getUuid().compareTo(node2.getUuid()); |
|
113 |
} |
|
114 |
} |
|
115 |
|
|
116 |
|
|
117 |
private String createSortableTitleCache(TaxonNodeDto taxonNode) { |
|
118 |
|
|
119 |
|
|
120 |
String nameTitleCache= taxonNode.getTitleCache(); |
|
121 |
|
|
122 |
if (nameTitleCache == null){ |
|
123 |
if (logger.isTraceEnabled()){logger.trace("titleCache still null, using taxonNode id");} |
|
124 |
nameTitleCache = String.valueOf(taxonNode.getId()); |
|
125 |
} |
|
126 |
if (logger.isTraceEnabled()){logger.trace("SortableTitleCache: " + nameTitleCache);} |
|
127 |
// System.out.println(titleCache); |
|
128 |
return nameTitleCache; |
|
129 |
} |
|
130 |
|
|
131 |
|
|
132 |
@Override |
|
133 |
public boolean isIgnoreHybridSign() { |
|
134 |
return ignoreHybridSign; |
|
135 |
} |
|
136 |
|
|
137 |
@Override |
|
138 |
public void setIgnoreHybridSign(boolean ignore) { |
|
139 |
this.ignoreHybridSign = ignore; |
|
140 |
} |
|
141 |
|
|
142 |
public boolean isSortInfraGenericFirst() { |
|
143 |
return sortInfraGenericFirst; |
|
144 |
} |
|
145 |
|
|
146 |
public void setSortInfraGenericFirst(boolean infraGenericFirst) { |
|
147 |
this.sortInfraGenericFirst = infraGenericFirst; |
|
148 |
} |
|
149 |
|
|
150 |
} |
|
151 |
|
|
152 |
|
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonNodeDtoByRankAndNameComparator.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2007 EDIT |
|
3 |
* European Distributed Institute of Taxonomy |
|
4 |
* http://www.e-taxonomy.eu |
|
5 |
* |
|
6 |
* The contents of this file are subject to the Mozilla Public License Version 1.1 |
|
7 |
* See LICENSE.TXT at the top of this package for the full license terms. |
|
8 |
*/ |
|
9 |
package eu.etaxonomy.cdm.api.service; |
|
10 |
|
|
11 |
import java.io.Serializable; |
|
12 |
import java.util.Comparator; |
|
13 |
import java.util.UUID; |
|
14 |
|
|
15 |
import eu.etaxonomy.cdm.model.name.Rank; |
|
16 |
import eu.etaxonomy.cdm.model.taxon.TaxonBase; |
|
17 |
import eu.etaxonomy.cdm.model.taxon.TaxonNode; |
|
18 |
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto; |
|
19 |
|
|
20 |
/** |
|
21 |
* @author k.luther |
|
22 |
* @since 18.03.2010 |
|
23 |
* |
|
24 |
*/ |
|
25 |
public class TaxonNodeDtoByRankAndNameComparator implements Serializable, Comparator<TaxonNodeDto> { |
|
26 |
private static final long serialVersionUID = 2596641007876609704L; |
|
27 |
|
|
28 |
@Override |
|
29 |
public int compare(TaxonNodeDto node1, TaxonNodeDto node2) { |
|
30 |
|
|
31 |
boolean node1Excluded = node1.isExcluded(); |
|
32 |
boolean node2Excluded = node2.isExcluded(); |
|
33 |
boolean node1Unplaced = node1.isUnplaced(); |
|
34 |
boolean node2Unplaced = node2.isUnplaced(); |
|
35 |
|
|
36 |
|
|
37 |
if (node1.getUuid().equals(node2.getUuid())){ |
|
38 |
return 0; |
|
39 |
} |
|
40 |
//They should both be put to the end (first unplaced then excluded) |
|
41 |
if (node2Excluded && !node1Excluded){ |
|
42 |
return -1; |
|
43 |
} |
|
44 |
if (node2Unplaced && !(node1Unplaced || node1Excluded)){ |
|
45 |
return -1; |
|
46 |
} |
|
47 |
|
|
48 |
if (node1Excluded && !node2Excluded){ |
|
49 |
return 1; |
|
50 |
} |
|
51 |
if (node1Unplaced && !(node2Unplaced || node2Excluded)){ |
|
52 |
return 1; |
|
53 |
} |
|
54 |
|
|
55 |
if (node1Unplaced && node2Excluded){ |
|
56 |
return -1; |
|
57 |
} |
|
58 |
if (node2Unplaced && node1Excluded){ |
|
59 |
return 1; |
|
60 |
} |
|
61 |
|
|
62 |
|
|
63 |
|
|
64 |
|
|
65 |
Rank rankTax1 = node1.getRank(); |
|
66 |
Rank rankTax2 = node2.getRank(); |
|
67 |
|
|
68 |
//first compare ranks, if ranks are equal (or both null) compare names or taxon title cache if names are null |
|
69 |
if (rankTax1 == null && rankTax2 != null){ |
|
70 |
return 1; |
|
71 |
}else if(rankTax2 == null && rankTax1 != null){ |
|
72 |
return -1; |
|
73 |
}else if (rankTax1 != null && rankTax1.isHigher(rankTax2)){ |
|
74 |
return -1; |
|
75 |
}else if (rankTax1 == null && rankTax2 == null || rankTax1.equals(rankTax2)) { |
|
76 |
if (node1.getTitleCache() != null && node2.getTitleCache() != null){ |
|
77 |
//same rank, order by name |
|
78 |
int result = node1.getNameTitleCache().compareTo(node2.getNameTitleCache()); |
|
79 |
if (result == 0){ |
|
80 |
return node1.getTaxonUuid().compareTo(node2.getTaxonUuid()); |
|
81 |
}else{ |
|
82 |
return result; |
|
83 |
} |
|
84 |
}else { |
|
85 |
//this is maybe not 100% correct, we need to compare name cases, but it is a very rare case |
|
86 |
return node1.getTaxonTitleCache().compareTo(node2.getTaxonTitleCache()); |
|
87 |
} |
|
88 |
}else{ |
|
89 |
//rankTax2.isHigher(rankTax1) |
|
90 |
return 1; |
|
91 |
} |
|
92 |
} |
|
93 |
|
|
94 |
/** |
|
95 |
* @param taxon1 |
|
96 |
* @return |
|
97 |
*/ |
|
98 |
public String getTaxonTitle(TaxonBase<?> taxon, TaxonNode node) { |
|
99 |
return (taxon == null) ? node.getUuid().toString(): taxon.getTitleCache(); |
|
100 |
} |
|
101 |
|
|
102 |
/** |
|
103 |
* @param taxon |
|
104 |
* @param node |
|
105 |
* @return |
|
106 |
*/ |
|
107 |
private UUID getTaxonUuid(TaxonBase<?> taxon, TaxonNode node) { |
|
108 |
return (taxon == null) ? node.getUuid(): taxon.getUuid(); |
|
109 |
} |
|
110 |
|
|
111 |
|
|
112 |
|
|
113 |
} |
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonNodeDtoNaturalComparator.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2007 EDIT |
|
3 |
* European Distributed Institute of Taxonomy |
|
4 |
* http://www.e-taxonomy.eu |
|
5 |
* |
|
6 |
* The contents of this file are subject to the Mozilla Public License Version 1.1 |
|
7 |
* See LICENSE.TXT at the top of this package for the full license terms. |
|
8 |
*/ |
|
9 |
package eu.etaxonomy.cdm.api.service; |
|
10 |
|
|
11 |
import java.util.Comparator; |
|
12 |
|
|
13 |
import eu.etaxonomy.cdm.model.taxon.TaxonNode; |
|
14 |
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto; |
|
15 |
|
|
16 |
/** |
|
17 |
* Comparator to compare {@link TaxonNode taxon nodes} by its user defined ordering |
|
18 |
* |
|
19 |
* @author k.luther |
|
20 |
*/ |
|
21 |
public class TaxonNodeDtoNaturalComparator implements Comparator<TaxonNodeDto> { |
|
22 |
|
|
23 |
public TaxonNodeDtoNaturalComparator(){ |
|
24 |
super(); |
|
25 |
|
|
26 |
} |
|
27 |
|
|
28 |
@SuppressWarnings("null") |
|
29 |
@Override |
|
30 |
public int compare(TaxonNodeDto node1, TaxonNodeDto node2) { |
|
31 |
// System.out.println("compare node 1: "+ node1.getTaxon().getTitleCache() + " - node 2: " + node2.getTaxon().getTitleCache()); |
|
32 |
if (node1.equals(node2)) { |
|
33 |
return 0; |
|
34 |
} |
|
35 |
// if we do not check for null for the treeIndex we always return 1 if one of the nodes have no treeIndex |
|
36 |
if (node1.getTreeIndex() == null){ |
|
37 |
return 1; |
|
38 |
} |
|
39 |
if (node2.getTreeIndex() == null){ |
|
40 |
return -1; |
|
41 |
} |
|
42 |
|
|
43 |
if (node1.getParentUUID().equals(node2.getParentUUID())){ |
|
44 |
return node1.getSortIndex().compareTo(node2.getSortIndex()); |
|
45 |
} |
|
46 |
|
|
47 |
|
|
48 |
if (node2.getTreeIndex().startsWith(node1.getTreeIndex())) { |
|
49 |
return -1; |
|
50 |
} |
|
51 |
if (node1.getTreeIndex().startsWith(node2.getTreeIndex())) { |
|
52 |
return 1; |
|
53 |
} |
|
54 |
|
|
55 |
|
|
56 |
// String[] splitNode1 = node1.getTreeIndex().split("#"); |
|
57 |
// String[] splitNode2 = node2.getTreeIndex().split("#"); |
|
58 |
|
|
59 |
|
|
60 |
|
|
61 |
// String lastEqualAncestorTreeIndex = ""; |
|
62 |
// List<TaxonNodeDto> ancestorAndNode= new ArrayList<>(); |
|
63 |
// ancestorAndNode.add(node1); |
|
64 |
// ancestorAndNode.addAll(node1.getAncestors()); |
|
65 |
// java.util.Collections.sort(ancestorAndNode, new TreeIndexComparator()); |
|
66 |
// |
|
67 |
// |
|
68 |
// List<TaxonNode> ancestorAndNode2= new ArrayList<>(); |
|
69 |
// ancestorAndNode2.add(node2); |
|
70 |
// ancestorAndNode2.addAll(node2.getAncestors()); |
|
71 |
// java.util.Collections.sort(ancestorAndNode2, new TreeIndexComparator()); |
|
72 |
// |
|
73 |
// for (int i = 0; i < splitNode1.length; i++){ |
|
74 |
// if (!splitNode1[i].equals(splitNode2[i])){ |
|
75 |
// // take the last equal ancestor and compare the sortindex |
|
76 |
// if (lastEqualAncestorTreeIndex != null){ |
|
77 |
// TaxonNode lastEqualTreeIndexAncestorNode1 = null; |
|
78 |
// TaxonNode lastEqualTreeIndexAncestorNode2 = null; |
|
79 |
// for (TaxonNode next1 :ancestorAndNode){ |
|
80 |
// |
|
81 |
// if (next1.treeIndex().equals(lastEqualAncestorTreeIndex+"#"+splitNode1[i]+ "#") ){ |
|
82 |
// lastEqualTreeIndexAncestorNode1 = next1; |
|
83 |
// } |
|
84 |
// } |
|
85 |
// for (TaxonNode next2 :ancestorAndNode2){ |
|
86 |
// |
|
87 |
// if (next2.treeIndex().equals(lastEqualAncestorTreeIndex+"#"+splitNode2[i]+ "#")){ |
|
88 |
// lastEqualTreeIndexAncestorNode2 = next2; |
|
89 |
// } |
|
90 |
// } |
|
91 |
// return lastEqualTreeIndexAncestorNode1.getSortIndex().compareTo(lastEqualTreeIndexAncestorNode2.getSortIndex()); |
|
92 |
// } |
|
93 |
// } |
|
94 |
// if (!splitNode1[i].equals("")){ |
|
95 |
// lastEqualAncestorTreeIndex = lastEqualAncestorTreeIndex+"#"+splitNode1[i]; |
|
96 |
// } |
|
97 |
// } |
|
98 |
return 0; |
|
99 |
} |
|
100 |
|
|
101 |
private final class TreeIndexComparator implements Comparator<TaxonNodeDto> { |
|
102 |
@Override |
|
103 |
public int compare(TaxonNodeDto node1,TaxonNodeDto node2){ |
|
104 |
return node1.getTreeIndex().compareTo(node2.getTreeIndex()); |
|
105 |
} |
|
106 |
} |
|
107 |
} |
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/TaxonNodeDtoByNameComparatorTest.java | ||
---|---|---|
27 | 27 |
import eu.etaxonomy.cdm.model.taxon.TaxonNode; |
28 | 28 |
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByNameComparator; |
29 | 29 |
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto; |
30 |
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDtoByNameComparator; |
|
30 | 31 |
|
31 | 32 |
/** |
32 | 33 |
* @author a.kohlbecker |
Also available in: Unified diff
ref #7939: add oderInderComnparator and use it in taxonnodeDtoRankAndNameComparator