Project

General

Profile

« Previous | Next » 

Revision d5d79aea

Added by Andreas Müller over 7 years ago

Improve sort order within a homotypic group (new Comparator) #3338

View differences:

cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/name/TaxonNameBase.java
702 702
        Set<TaxonNameBase> result = new HashSet<TaxonNameBase>();
703 703
        Set<NameRelationship> rels = this.getRelationsToThisName();
704 704
        for (NameRelationship rel : rels){
705
            if (rel.getType().isBasionymRelation()){
706
                TaxonNameBase basionym = rel.getFromName();
705
            if (rel.getType()!= null && rel.getType().isBasionymRelation()){
706
                TaxonNameBase<?,?> basionym = rel.getFromName();
707 707
                result.add(basionym);
708 708
            }
709 709
        }
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/HomotypicGroupTaxonComparator.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

  
10
package eu.etaxonomy.cdm.model.taxon;
11

  
12
import java.util.Comparator;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.Set;
16
import java.util.UUID;
17

  
18
import org.apache.log4j.Logger;
19

  
20
import eu.etaxonomy.cdm.model.name.NameRelationship;
21
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
22
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
23

  
24
/**
25
 * This class orders synonyms of a homotypic group,
26
 * first by
27
 * <ul>
28
 *  <li>Basionym groups (the basionym and all names derived from this basionym)
29
 *      should be kept together in a subgroup</li>
30
 *  <li>The order of the subgroups is defined by the ordering of their
31
 *       basionyms (according to the following ordering)</li>
32
 *  <li>If a name is illegitimate or not does play a role for ordering</li>
33
 *  <li>Names with publication year should always come first</li>
34
 *  <li>Names with no publication year are sorted alphabetically</li>
35
 *  <li>If 2 names have a replaced synonym relationship the replaced synonym comes first,
36
 *      the replacement name comes later as this reflects the order of publication</li>
37
 *  </ul>
38
 *
39
 * Details on ordering are explained at http://dev.e-taxonomy.eu/trac/ticket/3338<BR>
40
 *
41
 * @author a.mueller
42
 * @created 02.03.2016
43
 */
44
public class HomotypicGroupTaxonComparator extends TaxonComparator {
45
    private static final long serialVersionUID = -5088210641256430878L;
46
    @SuppressWarnings("unused")
47
	private static final Logger logger = Logger.getLogger(HomotypicGroupTaxonComparator.class);
48

  
49
    private final TaxonBase<?> firstTaxonInGroup;
50
    private final TaxonNameBase<?,?> firstNameInGroup;
51

  
52
    /**
53
     * @param firstNameInGroup
54
     */
55
    public HomotypicGroupTaxonComparator(@SuppressWarnings("rawtypes") TaxonBase firstTaxonInGroup) {
56
        this.firstTaxonInGroup = firstTaxonInGroup;
57
        this.firstNameInGroup = firstTaxonInGroup == null ? null: firstTaxonInGroup.getName();
58
    }
59

  
60
    /**
61
     *
62
     * @see TaxonComparator#compare(TaxonBase, TaxonBase)
63
     * @see java.lang.String#compareTo(String)
64
     * @see	java.util.Comparator#compare(java.lang.Object, java.lang.Object)
65
     */
66
    @Override
67
    public int compare(
68
            @SuppressWarnings("rawtypes") TaxonBase taxonBase1,
69
            @SuppressWarnings("rawtypes") TaxonBase taxonBase2) {
70

  
71
        TaxonNameBase<?,?> name1 = taxonBase1.getName();
72
        TaxonNameBase<?,?> name2 = taxonBase2.getName();
73
        System.out.print(name1.getTitleCache() +" : "+ name2.getTitleCache());
74

  
75

  
76
        int compareStatus = compareStatus(name1, name2);
77
        if (compareStatus != 0){
78
            return compareStatus;
79
        }
80

  
81
        //not same homotypical group -
82
        //NOTE: this comparator should usually not be used
83
        //      for comparing names of different homotypcial groups.
84
        //      The following is only to have a defined compare behavior
85
        //      which follows the contract of Comparator#compare.
86
        if (name1 == null ||
87
            name2 == null ||
88
            ! name1.getHomotypicalGroup().equals(name2.getHomotypicalGroup())){
89

  
90
            int result = name1.getHomotypicalGroup().getUuid().toString()
91
                    .compareTo(name2.getHomotypicalGroup().getUuid().toString());
92
            System.out.println(": t" + result);
93
            System.out.println(name1.getHomotypicalGroup().getUuid());
94
            System.out.println(name2.getHomotypicalGroup().getUuid());
95
            return result;
96
        }
97

  
98
        //same homotypical group ...
99
        //one taxon is first in group
100
        if (taxonBase1.equals(firstTaxonInGroup)){
101
            return -1;
102
        }else if (taxonBase2.equals(firstTaxonInGroup)){
103
            return 1;
104
        }
105

  
106
        System.out.print("_");
107
        //same name => compare on taxon level
108
        if (name1.equals(name2)){
109
            return super.compare(taxonBase1, taxonBase2);  //if name is the same compare on taxon level
110
        }
111
        System.out.print("_");
112

  
113
        TaxonNameBase<?,?> basionym1 = getPreferredInBasionymGroup(name1);
114
        TaxonNameBase<?,?> basionym2 = getPreferredInBasionymGroup(name2);
115

  
116
        int compareResult;
117
        if (basionym1.equals(basionym2)){
118
            //both names belong to same basionym sub-group
119
            compareResult = handleSameBasionym(basionym1, name1, name2);
120
        }else{
121
            compareResult = compareBasionyms(basionym1, basionym2);
122
        }
123

  
124
        if (compareResult != 0){
125
            System.out.println(": " + compareResult);
126
            return compareResult;
127
        }else{
128
            //names are uncomparable on name level (except for uuid, id, etc.)
129

  
130
            int result = super.compare(taxonBase1, taxonBase2);
131
            System.out.println(": = " + result);
132
            return result;
133
        }
134
    }
135

  
136
//    /**
137
//     * @param homotypicalGroup
138
//     * @return
139
//     */
140
//    private TaxonBase<?> getFirstInHomotypicalGroup(HomotypicalGroup homotypicalGroup, Collection<TaxonBase<?>> existing) {
141
//        List<TaxonBase<?>> candidates =  new ArrayList<TaxonBase<?>>();
142
//        for (TaxonBase<?> candidate : existing){
143
//            if (homotypicalGroup.getTypifiedNames().contains(candidate.getName())){
144
//                candidates.add(candidate);
145
//            }
146
//        }
147
//        Collections.sort(candidates, this);
148
//        return candidates.isEmpty() ? null : candidates.get(0);
149
//    }
150

  
151
    /**
152
     * Compare 2 names which have the same basionym.
153
     * The names must not be equal to each other but may be equal
154
     * to the basionym.
155
     * @param basionym the basionym
156
     * @param name1 first name to compare
157
     * @param name2 second name to compare
158
     * @return compare value according to the {@link Comparator#compare(Object, Object)} contract.
159
     */
160
    private int handleSameBasionym(TaxonNameBase<?, ?> basionym,
161
            TaxonNameBase<?, ?> name1,
162
            TaxonNameBase<?, ?> name2) {
163

  
164
        if (basionym.equals(name1)){
165
            return -1;
166
        }else if (basionym.equals(name2)){
167
            return 1;
168
        }else{
169
            super.compare(name1, name2);
170
        }
171
        return 0;
172
    }
173

  
174
    /**
175
     * @param basionym1
176
     * @param basionym2
177
     * @return
178
     */
179
    private int compareBasionyms(TaxonNameBase<?,?> basionym1Orig, TaxonNameBase<?,?> basionym2Orig) {
180
        //one taxon is first in group
181
        TaxonNameBase<?,?> basionym1 = getFirstNameInGroup(basionym1Orig);
182
        TaxonNameBase<?,?> basionym2 = getFirstNameInGroup(basionym2Orig);
183

  
184
        if (basionym1.equals(firstNameInGroup)){
185
            return -1;
186
        }else if (basionym2.equals(firstTaxonInGroup)){
187
            return 1;
188
        }
189

  
190
        if (getReplacedSynonymClosure(basionym1).contains(basionym2)){
191
            return 1;
192
        }else if (getReplacedSynonymClosure(basionym2).contains(basionym1)){
193
            return -1;
194
        }
195

  
196
        int result = super.compare(basionym1, basionym2);
197
        return result;
198

  
199

  
200
    }
201

  
202
    /**
203
     * @param basionym
204
     * @return
205
     */
206
    private TaxonNameBase<?, ?> getFirstNameInGroup(TaxonNameBase<?, ?> basionym) {
207
        for (NameRelationship nameRel : basionym.getRelationsFromThisName()){
208
            if (nameRel.getType() != null && nameRel.getType().equals(NameRelationshipType.BASIONYM())){
209
                if (nameRel.getToName().equals(firstNameInGroup)){
210
                    return firstNameInGroup;
211
                }
212
            }
213
        }
214
        return basionym;
215
    }
216

  
217
    /**
218
     * @param basionym1
219
     * @return
220
     */
221
    @SuppressWarnings("rawtypes")
222
    private Set<TaxonNameBase> getReplacedSynonymClosure(TaxonNameBase<?, ?> name) {
223
        Set<TaxonNameBase> set = name.getReplacedSynonyms();
224
        if (set.isEmpty()){
225
            return set;
226
        }
227
        Set<TaxonNameBase> result = new HashSet<TaxonNameBase>();
228
        for (TaxonNameBase<?,?> replSyn : set){
229
            boolean notYetContained = result.add(replSyn);
230
            if (notYetContained){
231
                result.addAll(replSyn.getReplacedSynonyms());
232
            }
233
        }
234
        return result;
235
    }
236

  
237
    /**
238
     * @param name1
239
     * @return
240
     */
241
    private TaxonNameBase<?,?> getPreferredInBasionymGroup(TaxonNameBase<?,?> name) {
242
        HashMap<UUID, TaxonNameBase<?,?>> candidates = new HashMap<UUID, TaxonNameBase<?,?>>();
243
        for (TaxonNameBase<?,?> candidate : name.getBasionyms()){
244
            if (candidate != null && candidate.getHomotypicalGroup().equals(name.getHomotypicalGroup())){
245
                candidates.put(candidate.getUuid(), candidate);
246
            }
247
        }
248

  
249
        if (candidates.isEmpty()){
250
            return name;
251
        }else{
252
            return candidates.get(candidates.keySet().iterator().next());
253
        }
254
    }
255

  
256

  
257
}
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/Taxon.java
1704 1704
     */
1705 1705
    @Transient
1706 1706
    public List<Synonym> getSynonymsInGroup(HomotypicalGroup homotypicGroup){
1707
        return getSynonymsInGroup(homotypicGroup, new TaxonComparator());
1708
    }
1709

  
1710
    /**
1711
     * @param homotypicGroup
1712
     * @param comparator
1713
     * @return
1714
     * @see {@link #getSynonymsInGroup(HomotypicalGroup)}
1715
     */
1716
    @Transient
1717
    public List<Synonym> getSynonymsInGroup(HomotypicalGroup homotypicGroup, TaxonComparator comparator){
1707 1718
        List<Synonym> result = new ArrayList<Synonym>();
1708 1719

  
1709 1720
        for (TaxonNameBase<?, ?>name : homotypicGroup.getTypifiedNames()){
......
1715 1726
                }
1716 1727
            }
1717 1728
        }
1718
        Collections.sort(result, new TaxonComparator());
1729
        Collections.sort(result, comparator);
1719 1730
        return result;
1720 1731
    }
1721 1732

  
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/TaxonComparator.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

  
10
package eu.etaxonomy.cdm.model.taxon;
11

  
12
import java.io.Serializable;
13
import java.util.Comparator;
14
import java.util.Set;
15

  
16
import org.apache.log4j.Logger;
17

  
18
import org.joda.time.DateTime;
19

  
20
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
21
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
22
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
23
import eu.etaxonomy.cdm.model.name.ZoologicalName;
24
import eu.etaxonomy.cdm.model.reference.Reference;
25

  
26
/**
27
 * This class makes available a method to compare two {@link TaxonBase taxa} by
28
 * comparing the publication dates of the corresponding 
29
 * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon names}.
30
 *
31
 * @author a.mueller
32
 * @created 11.06.2008
33
 */
34
public class TaxonComparator implements Comparator<TaxonBase>, Serializable {
35
	private static final long serialVersionUID = -1433623743189043446L;
36
	@SuppressWarnings("unused")
37
	private static final Logger logger = Logger.getLogger(TaxonComparator.class);
38

  
39
    /**
40
     * Returns an integer generated by comparing first the nomenclatural status and then the 
41
     * {@link eu.etaxonomy.cdm.model.name.INomenclaturalReference#getYear() publication years}
42
     * of both {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon names} 
43
     * used in the given {@link TaxonBase taxa}.
44
     * If 1 name has status of type nom.inval. or nom.nudum the name is but to the end in a
45
     * list (returns +1 for a status in taxon1 and -1 for a status in taxon2). If both do have
46
     * no status or the same status, the publication date is taken for comparison.
47
     * Nom. nudum is handled as more "severe" status then nom.inval.
48
     *  
49
     * Returns a negative value if the publication year corresponding to the
50
     * first given taxon precedes the publication year corresponding to the
51
     * second given taxon. Returns a positive value if the contrary is true and
52
     * 0 if both publication years and the date, when they are created, are identical. 
53
     * In case one of the publication
54
     * years is "null" and the other is not, the "empty" publication year will
55
     * be considered to be always preceded by the "not null" publication year.
56
     * If both publication years are "null" the creation date is used for the comparison
57
     *
58
     *
59
     * @see		java.lang.String#compareTo(String)
60
     * @see		java.util.Comparator#compare(java.lang.Object, java.lang.Object)
61
     */
62
    public int compare(TaxonBase taxonBase1, TaxonBase taxonBase2) {
63
        int result;
64

  
65
        if (taxonBase1.equals(taxonBase2)){
66
        	return 0;
67
        }
68
        
69
        //set to end if a taxon has nomenclatural status "nom. inval." or "nom. nud."
70
        int statusCompareWeight = 0;
71
        statusCompareWeight += computeStatusCompareWeight(taxonBase1);
72
        statusCompareWeight -= computeStatusCompareWeight(taxonBase2);
73
        
74
        if (statusCompareWeight != 0){
75
        	return Integer.signum(statusCompareWeight);
76
        }
77
        
78
        //dates
79
        Integer intDate1 = getIntegerDate(taxonBase1);
80
        Integer intDate2 = getIntegerDate(taxonBase2);
81

  
82
        if (intDate1 == null && intDate2 == null){
83
            result = 0;
84
        }else if (intDate1 == null){
85
            return 1;
86
        }else if (intDate2 == null){
87
            return -1;
88
        }else{
89
            result = intDate1.compareTo(intDate2);
90
        }
91

  
92
        if (result == 0){
93
            TaxonNameBase<?,?> taxName1 = taxonBase1.getName();
94
            TaxonNameBase<?,?> taxName2 = taxonBase2.getName();
95

  
96
            result = taxName1.compareTo(taxName2);
97
            if (result != 0){
98
            	return result;
99
            }
100
        }
101

  
102
        if (result == 0){
103
            DateTime date11 = taxonBase1.getCreated();
104
            DateTime date12 = taxonBase2.getCreated();
105
            if (date11 == null && date12 == null) {
106
                result = 0;
107
            }else if (date11 == null) {
108
                return 1;
109
            }else if (date12 == null) {
110
                return -1;
111
            }else{
112
            	result = date11.compareTo(date12);
113
            }
114
        }
115
        if (result == 0){
116
        	//the Comparator contract 
117
        	return taxonBase1.getUuid().compareTo(taxonBase1.getUuid());
118
        }else{
119
        	return result;
120
        }
121
    }
122

  
123

  
124
	/**
125
	 * @param taxonBase1
126
	 * @param statusCompareWeight
127
	 * @return
128
	 */
129
	private int computeStatusCompareWeight(TaxonBase<?> taxonBase) {
130
		int result = 0;
131
		if (taxonBase == null || taxonBase.getName() == null || taxonBase.getName().getStatus() == null){
132
			return 0;
133
		}
134
		Set<NomenclaturalStatus> status1 = taxonBase.getName().getStatus();
135
        for (NomenclaturalStatus nomStatus1 : status1){
136
            if (nomStatus1.getType() != null){
137
            	if (nomStatus1.getType().equals(NomenclaturalStatusType.INVALID())){
138
            		result += 1;
139
            	}else if(nomStatus1.getType().equals(NomenclaturalStatusType.NUDUM())){
140
            		result += 2;
141
                }
142
            }
143
        }
144
		return result;
145
	}
146

  
147

  
148
    private Integer getIntegerDate(TaxonBase<?> taxonBase){
149
        Integer result;
150

  
151
        if (taxonBase == null){
152
            result = null;
153
        }else{
154
            TaxonNameBase<?,?> name = taxonBase.getName();
155
           if (name == null){
156
                result = null;
157
            }else{
158
                if (name instanceof ZoologicalName){
159
                    result = (((ZoologicalName)name).getPublicationYear());
160
                }else{
161
                    Reference<?> ref = (Reference<?>) name.getNomenclaturalReference();
162
                    if (ref == null){
163
                        result = null;
164
                    }else{
165
                        if (ref.getDatePublished() == null){
166
                        	Reference<?> inRef = ref.getInReference();
167
                        	if (inRef == null){
168
                                result = null;
169
                            }else{
170
                                if (inRef.getDatePublished() == null){
171
                                	result = null;
172
                                }else{
173
                                	result = ref.getInReference().getDatePublished().getStartYear();
174
                                }
175
                            }
176
                        }else{
177
                            result = ref.getDatePublished().getStartYear();
178
                        }
179
                    }
180
                }
181
            }
182
        }
183

  
184
        return result;
185
    }
186

  
187

  
188
}
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

  
10
package eu.etaxonomy.cdm.model.taxon;
11

  
12
import java.io.Serializable;
13
import java.util.Comparator;
14
import java.util.Set;
15

  
16
import org.apache.log4j.Logger;
17
import org.joda.time.DateTime;
18

  
19
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
20
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
21
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
22
import eu.etaxonomy.cdm.model.name.ZoologicalName;
23
import eu.etaxonomy.cdm.model.reference.Reference;
24

  
25
/**
26
 * This class makes available a method to compare two {@link TaxonBase taxa} by
27
 * comparing the publication dates of the corresponding
28
 * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon names}.
29
 *
30
 * @author a.mueller
31
 * @created 11.06.2008
32
 */
33
public class TaxonComparator implements Comparator<TaxonBase>, Serializable {
34
	private static final long serialVersionUID = -1433623743189043446L;
35
	@SuppressWarnings("unused")
36
	private static final Logger logger = Logger.getLogger(TaxonComparator.class);
37

  
38
    /**
39
     * Returns an integer generated by comparing first the nomenclatural status and then the
40
     * {@link eu.etaxonomy.cdm.model.name.INomenclaturalReference#getYear() publication years}
41
     * of both {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon names}
42
     * used in the given {@link TaxonBase taxa}.
43
     * If 1 name has status of type nom. inval. or nom. nudum the name is put to the end of a
44
     * list (returns +1 for a status in taxon1 and -1 for a status in taxon2). If both do have
45
     * no status or the same status, the publication date is taken for comparison.
46
     * Nom. nudum is handled as more "severe" status then nom.inval.
47
     *
48
     * Returns a negative value if the publication year corresponding to the
49
     * first given taxon precedes the publication year corresponding to the
50
     * second given taxon. Returns a positive value if the contrary is true and
51
     * 0 if both publication years and the date, when they are created, are identical.
52
     * In case one of the publication
53
     * years is "null" and the other is not, the "empty" publication year will
54
     * be considered to be always preceded by the "not null" publication year.
55
     * If both publication years are "null" the creation date is used for the comparison
56
     *
57
     *
58
     * @see		java.lang.String#compareTo(String)
59
     * @see		java.util.Comparator#compare(java.lang.Object, java.lang.Object)
60
     */
61
    @Override
62
    public int compare(
63
            @SuppressWarnings("rawtypes") TaxonBase taxonBase1,
64
            @SuppressWarnings("rawtypes") TaxonBase taxonBase2) {
65
        int result;
66

  
67
        if (taxonBase1.equals(taxonBase2)){
68
        	return 0;
69
        }
70

  
71
        TaxonNameBase<?,?> name1 = taxonBase1.getName();
72
        TaxonNameBase<?,?> name2 = taxonBase2.getName();
73

  
74
        //set to end if a taxon has nomenclatural status "nom. inval." or "nom. nud."
75
        int statusCompareWeight = compareStatus(name1, name2);
76

  
77
        if (statusCompareWeight != 0){
78
        	return Integer.signum(statusCompareWeight);
79
        }
80

  
81
        result = compare(name1, name2);
82

  
83
        if (result == 0){
84
            DateTime date11 = taxonBase1.getCreated();
85
            DateTime date12 = taxonBase2.getCreated();
86
            if (date11 == null && date12 == null) {
87
                result = 0;
88
            }else if (date11 == null) {
89
                return 1;
90
            }else if (date12 == null) {
91
                return -1;
92
            }else{
93
            	result = date11.compareTo(date12);
94
            }
95
        }
96
        if (result == 0){
97
        	//the Comparator contract
98
        	return taxonBase1.getUuid().compareTo(taxonBase1.getUuid());
99
        }else{
100
        	return result;
101
        }
102
    }
103

  
104

  
105
    /**
106
     * @param taxonNameBase
107
     * @param taxonNameBase2
108
     * @param statusCompareWeight
109
     * @return
110
     */
111
    protected int compareStatus(TaxonNameBase<?,?> taxonNameBase, TaxonNameBase<?,?> taxonNameBase2) {
112
        int statusCompareWeight = 0;
113
        statusCompareWeight += computeStatusCompareWeight(taxonNameBase);
114
        statusCompareWeight -= computeStatusCompareWeight(taxonNameBase2);
115
        return statusCompareWeight;
116
    }
117

  
118

  
119
	/**
120
	 * @param taxonBase1
121
	 * @param statusCompareWeight
122
	 * @return
123
	 */
124
	private int computeStatusCompareWeight(TaxonNameBase<?,?> taxonNameBase) {
125
		int result = 0;
126
		if (taxonNameBase == null || taxonNameBase.getStatus() == null){
127
			return 0;
128
		}
129
		Set<NomenclaturalStatus> status1 = taxonNameBase.getStatus();
130
        for (NomenclaturalStatus nomStatus1 : status1){
131
            if (nomStatus1.getType() != null){
132
            	if (nomStatus1.getType().equals(NomenclaturalStatusType.INVALID())){
133
            		result += 1;
134
            	}else if(nomStatus1.getType().equals(NomenclaturalStatusType.NUDUM())){
135
            		result += 2;
136
                }
137
            }
138
        }
139
		return result;
140
	}
141

  
142

  
143
    private Integer getIntegerDate(TaxonNameBase<?,?> name){
144
        Integer result;
145

  
146
       if (name == null){
147
            result = null;
148
        }else{
149
            if (name instanceof ZoologicalName){
150
                result = (((ZoologicalName)name).getPublicationYear());
151
            }else{
152
                Reference<?> ref = (Reference<?>) name.getNomenclaturalReference();
153
                if (ref == null){
154
                    result = null;
155
                }else{
156
                    if (ref.getDatePublished() == null){
157
                    	Reference<?> inRef = ref.getInReference();
158
                    	if (inRef == null){
159
                            result = null;
160
                        }else{
161
                            if (inRef.getDatePublished() == null){
162
                            	result = null;
163
                            }else{
164
                            	result = ref.getInReference().getDatePublished().getStartYear();
165
                            }
166
                        }
167
                    }else{
168
                        result = ref.getDatePublished().getStartYear();
169
                    }
170
                }
171
            }
172
        }
173

  
174
        return result;
175
    }
176

  
177

  
178
    /**
179
     *
180
     * @param name1
181
     * @param name2
182
     * @return
183
     */
184
    protected int compare(TaxonNameBase<?,?> name1, TaxonNameBase<?,?> name2) {
185
        int result;
186

  
187
        //dates
188
        Integer intDate1 = getIntegerDate(name1);
189
        Integer intDate2 = getIntegerDate(name2);
190

  
191
        if (intDate1 == null && intDate2 == null){
192
            result = 0;
193
        }else if (intDate1 == null){
194
            return 1;
195
        }else if (intDate2 == null){
196
            return -1;
197
        }else{
198
            result = intDate1.compareTo(intDate2);
199
        }
200

  
201
        if (result == 0){
202
            result = name1.compareTo(name2);
203
            if (result != 0){
204
                return result;
205
            }
206
        }
207
        return result;
208
    }
209

  
210

  
211
}
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/TaxonNaturalComparator.java
1
package eu.etaxonomy.cdm.model.taxon;
2

  
3
import java.util.Comparator;
4
import java.util.Iterator;
5

  
6
public class TaxonNaturalComparator implements Comparator<TaxonNode> {
7
	Classification classification;
8

  
9
	public TaxonNaturalComparator(){
10
		super();
11

  
12
	}
13

  
14
	@Override
15
	public int compare(TaxonNode node1, TaxonNode node2) {
16
//		TaxonNode node1 = null;
17
//		TaxonNode node2 = null;
18
//		if (taxon1.getTaxonNodes().size()>0 && taxon2.getTaxonNodes().size()>0){
19
//			for (TaxonNode node: taxon1.getTaxonNodes()){
20
//				if (node.getClassification().equals(classification)){
21
//					node1= node;
22
//					break;
23
//				}
24
//			}
25
//			for (TaxonNode node: taxon2.getTaxonNodes()){
26
//				if (node.getClassification().equals(classification)){
27
//					node2= node;
28
//					break;
29
//				}
30
//			}
31
//		}else{
32
//			return 0;
33
//		}
34
		if (node1.isAncestor(node2)) {
35
            return 1;
36
        }
37
		if (node2.isAncestor(node1)) {
38
            return -1;
39
        }
40
		if (node1.equals(node2)) {
41
            return 0;
42
        }
43

  
44
		String[] splitNode1 = node1.treeIndex().split("#");
45
		String[] splitNode2 = node2.treeIndex().split("#");
46
		if (splitNode1.length < splitNode2.length) {
47
            return 1;
48
        } else if (splitNode2.length < splitNode1.length) {
49
            return -1;
50
        }
51

  
52
		if (node1.getParent().equals(node2.getParent())){
53
			return node1.getSortIndex().compareTo(node2.getSortIndex());
54
		}
55
		String lastEqualAncestorTreeIndex = null;
56

  
57
		Iterator<TaxonNode> ancestorsNode1 = node1.getAncestors().iterator();
58
		Iterator<TaxonNode> ancestorsNode2 = node2.getAncestors().iterator();
59
		for (int i = 0; i < splitNode1.length; i++){
60
			if (!splitNode1[i].equals(splitNode2[i])){
61
				// take the last equal ancestor and compare the sortindex
62
				if (lastEqualAncestorTreeIndex != null){
63
					TaxonNode lastEqualTreeIndexAncestorNode1 = null;
64
					TaxonNode lastEqualTreeIndexAncestorNode2 = null;
65
					while (ancestorsNode1.hasNext()){
66
						TaxonNode next1 = ancestorsNode1.next();
67
						if (next1.treeIndex().equals(lastEqualAncestorTreeIndex)){
68
							lastEqualTreeIndexAncestorNode1 = next1;
69
						}
70
					}
71
					while (ancestorsNode2.hasNext()){
72
						TaxonNode next2 = ancestorsNode2.next();
73
						if (next2.treeIndex().equals(lastEqualAncestorTreeIndex)){
74
							lastEqualTreeIndexAncestorNode2 = next2;
75
						}
76
					}
77
					return lastEqualTreeIndexAncestorNode1.getSortIndex().compareTo(lastEqualTreeIndexAncestorNode2.getSortIndex());
78

  
79
				}
80
			}
81
			lastEqualAncestorTreeIndex = splitNode1[i];
82
		}
83

  
84
		return 0;
85
	}
86

  
87
}
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.model.taxon;
10

  
11
import java.util.Comparator;
12
import java.util.Iterator;
13

  
14
/**
15
 * Comparator to compare {@link TaxonNode taxon nodes} by its user defined ordering
16
 * @author k.luther
17
 */
18
public class TaxonNaturalComparator implements Comparator<TaxonNode> {
19

  
20
    public TaxonNaturalComparator(){
21
		super();
22

  
23
	}
24

  
25
	@Override
26
	public int compare(TaxonNode node1, TaxonNode node2) {
27
//		TaxonNode node1 = null;
28
//		TaxonNode node2 = null;
29
//		if (taxon1.getTaxonNodes().size()>0 && taxon2.getTaxonNodes().size()>0){
30
//			for (TaxonNode node: taxon1.getTaxonNodes()){
31
//				if (node.getClassification().equals(classification)){
32
//					node1= node;
33
//					break;
34
//				}
35
//			}
36
//			for (TaxonNode node: taxon2.getTaxonNodes()){
37
//				if (node.getClassification().equals(classification)){
38
//					node2= node;
39
//					break;
40
//				}
41
//			}
42
//		}else{
43
//			return 0;
44
//		}
45
		if (node1.isAncestor(node2)) {
46
            return 1;
47
        }
48
		if (node2.isAncestor(node1)) {
49
            return -1;
50
        }
51
		if (node1.equals(node2)) {
52
            return 0;
53
        }
54

  
55
		String[] splitNode1 = node1.treeIndex().split("#");
56
		String[] splitNode2 = node2.treeIndex().split("#");
57
		if (splitNode1.length < splitNode2.length) {
58
            return 1;
59
        } else if (splitNode2.length < splitNode1.length) {
60
            return -1;
61
        }
62

  
63
		if (node1.getParent().equals(node2.getParent())){
64
			return node1.getSortIndex().compareTo(node2.getSortIndex());
65
		}
66
		String lastEqualAncestorTreeIndex = null;
67

  
68
		Iterator<TaxonNode> ancestorsNode1 = node1.getAncestors().iterator();
69
		Iterator<TaxonNode> ancestorsNode2 = node2.getAncestors().iterator();
70
		for (int i = 0; i < splitNode1.length; i++){
71
			if (!splitNode1[i].equals(splitNode2[i])){
72
				// take the last equal ancestor and compare the sortindex
73
				if (lastEqualAncestorTreeIndex != null){
74
					TaxonNode lastEqualTreeIndexAncestorNode1 = null;
75
					TaxonNode lastEqualTreeIndexAncestorNode2 = null;
76
					while (ancestorsNode1.hasNext()){
77
						TaxonNode next1 = ancestorsNode1.next();
78
						if (next1.treeIndex().equals(lastEqualAncestorTreeIndex)){
79
							lastEqualTreeIndexAncestorNode1 = next1;
80
						}
81
					}
82
					while (ancestorsNode2.hasNext()){
83
						TaxonNode next2 = ancestorsNode2.next();
84
						if (next2.treeIndex().equals(lastEqualAncestorTreeIndex)){
85
							lastEqualTreeIndexAncestorNode2 = next2;
86
						}
87
					}
88
					return lastEqualTreeIndexAncestorNode1.getSortIndex().compareTo(lastEqualTreeIndexAncestorNode2.getSortIndex());
89

  
90
				}
91
			}
92
			lastEqualAncestorTreeIndex = splitNode1[i];
93
		}
94

  
95
		return 0;
96
	}
97

  
98
}
cdmlib-model/src/test/java/eu/etaxonomy/cdm/model/taxon/TaxonComparatorTest.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

  
10
package eu.etaxonomy.cdm.model.taxon;
11

  
12
import java.util.ArrayList;
13
import java.util.Calendar;
14
import java.util.Collections;
15
import java.util.List;
16

  
17
import org.apache.log4j.Logger;
18
import org.junit.After;
19
import org.junit.AfterClass;
20
import org.junit.Before;
21
import org.junit.BeforeClass;
22
import org.junit.Test;
23

  
24
import eu.etaxonomy.cdm.model.common.TimePeriod;
25
import eu.etaxonomy.cdm.model.name.BotanicalName;
26
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
27
import eu.etaxonomy.cdm.model.name.ZoologicalName;
28
//import eu.etaxonomy.cdm.model.reference.Book;
29
import eu.etaxonomy.cdm.model.reference.Reference;
30
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
31

  
32
/**
33
 * @author a.mueller
34
 * @created 11.06.2008
35
 * @version 1.0
36
 */
37
public class TaxonComparatorTest {
38
    private static final Logger logger = Logger.getLogger(TaxonComparatorTest.class);
39

  
40
    /**
41
     * @throws java.lang.Exception
42
     */
43
    @BeforeClass
44
    public static void setUpBeforeClass() throws Exception {
45
    }
46

  
47
    /**
48
     * @throws java.lang.Exception
49
     */
50
    @AfterClass
51
    public static void tearDownAfterClass() throws Exception {
52
    }
53

  
54
    /**
55
     * @throws java.lang.Exception
56
     */
57
    @Before
58
    public void setUp() throws Exception {
59
    }
60

  
61
    /**
62
     * @throws java.lang.Exception
63
     */
64
    @After
65
    public void tearDown() throws Exception {
66
    }
67

  
68
/******************** TESTS *****************************************************/
69

  
70
    /**
71
     * Test method for {@link eu.etaxonomy.cdm.model.taxon.TaxonComparator#compare(eu.etaxonomy.cdm.model.taxon.TaxonBase, eu.etaxonomy.cdm.model.taxon.TaxonBase)}.
72
     */
73
    @Test
74
    public void testCompare() {
75
        logger.debug("start testCompare");
76

  
77
        Reference sec = ReferenceFactory.newBook();
78

  
79
        Reference ref1 = ReferenceFactory.newBook();
80
        Reference ref2 = ReferenceFactory.newBook();
81
        Reference ref3 = ReferenceFactory.newBook();
82
        Calendar cal1 = Calendar.getInstance();
83
        Calendar cal2 = Calendar.getInstance();
84
        Calendar cal3 = Calendar.getInstance();
85
        cal1.set(1945, 3, 2);
86
        cal2.set(1856, 3, 2);
87
        cal3.set(1943, 3, 2);
88

  
89
        ref1.setDatePublished(TimePeriod.NewInstance(cal1));
90
//		ref2.setDatePublished(TimePeriod.NewInstance(cal2));
91
        ref3.setDatePublished(TimePeriod.NewInstance(cal3));
92

  
93
        BotanicalName botName1 =  BotanicalName.NewInstance(null);
94
        BotanicalName botName2 =  BotanicalName.NewInstance(null);
95
        BotanicalName botName3 =  BotanicalName.NewInstance(null);
96
        ZoologicalName zooName1 = ZoologicalName.NewInstance(null);
97

  
98
        botName1.setNomenclaturalReference(ref1);
99
        botName2.setNomenclaturalReference(ref2);
100
        botName3.setNomenclaturalReference(ref3);
101
        zooName1.setPublicationYear(1823);
102

  
103
        List<TaxonBase> list = new ArrayList<TaxonBase>();
104

  
105
        Taxon taxon1 = Taxon.NewInstance(botName1, sec);
106
        Taxon taxon2 = Taxon.NewInstance(botName2, sec);
107
        Taxon taxon3 = Taxon.NewInstance(botName3, sec);
108
        Taxon zooTaxon4 = Taxon.NewInstance(zooName1, sec);
109

  
110
        taxon1.setId(1);
111
        taxon2.setId(2);
112
        taxon3.setId(3);
113
        zooTaxon4.setId(4);
114

  
115

  
116
        list.add(taxon3);
117
        list.add(taxon2);
118
        list.add(taxon1);
119
        list.add(zooTaxon4);
120
        Collections.sort(list, new TaxonComparator());
121

  
122
        for (TaxonBase taxon : list){
123
            String year = "";
124
            TaxonNameBase<?,?> tnb = taxon.getName();
125
            if (tnb instanceof ZoologicalName){
126
                year = String.valueOf(((ZoologicalName)tnb).getPublicationYear());
127
            }else{
128
                year = tnb.getNomenclaturalReference().getYear();
129
            }
130
            System.out.println(taxon.getId() + ": " + year);
131
        }
132
    }
133
}
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

  
10
package eu.etaxonomy.cdm.model.taxon;
11

  
12
import java.util.ArrayList;
13
import java.util.Calendar;
14
import java.util.Collections;
15
import java.util.List;
16

  
17
import org.apache.log4j.Logger;
18
import org.junit.Assert;
19
import org.junit.BeforeClass;
20
import org.junit.Test;
21

  
22
import eu.etaxonomy.cdm.model.common.TimePeriod;
23
import eu.etaxonomy.cdm.model.name.BotanicalName;
24
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
25
import eu.etaxonomy.cdm.model.name.ZoologicalName;
26
//import eu.etaxonomy.cdm.model.reference.Book;
27
import eu.etaxonomy.cdm.model.reference.Reference;
28
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
29

  
30
/**
31
 * @author a.mueller
32
 * @created 11.06.2008
33
 */
34
public class TaxonComparatorTest {
35
    private static final Logger logger = Logger.getLogger(TaxonComparatorTest.class);
36

  
37
    /**
38
     * @throws java.lang.Exception
39
     */
40
    @BeforeClass
41
    public static void setUpBeforeClass() throws Exception {
42
    }
43

  
44

  
45
/******************** TESTS *****************************************************/
46

  
47
    /**
48
     * Test method for {@link eu.etaxonomy.cdm.model.taxon.TaxonComparator#compare(eu.etaxonomy.cdm.model.taxon.TaxonBase, eu.etaxonomy.cdm.model.taxon.TaxonBase)}.
49
     */
50
    @Test
51
    public void testCompare() {
52

  
53
        Reference<?> sec = ReferenceFactory.newBook();
54

  
55
        Reference<?> ref1 = ReferenceFactory.newBook();
56
        Reference<?> ref2 = ReferenceFactory.newBook();
57
        Reference<?> ref3 = ReferenceFactory.newBook();
58
        Calendar cal1 = Calendar.getInstance();
59
        Calendar cal2 = Calendar.getInstance();
60
        Calendar cal3 = Calendar.getInstance();
61
        cal1.set(1945, 3, 2);
62
        cal2.set(1856, 3, 2);
63
        cal3.set(1943, 3, 2);
64

  
65
        ref1.setDatePublished(TimePeriod.NewInstance(cal1));
66
//		ref2.setDatePublished(TimePeriod.NewInstance(cal2));
67
        ref3.setDatePublished(TimePeriod.NewInstance(cal3));
68

  
69
        BotanicalName botName1 =  BotanicalName.NewInstance(null);
70
        BotanicalName botName2 =  BotanicalName.NewInstance(null);
71
        BotanicalName botName3 =  BotanicalName.NewInstance(null);
72
        ZoologicalName zooName1 = ZoologicalName.NewInstance(null);
73

  
74
        botName1.setNomenclaturalReference(ref1);
75
        botName2.setNomenclaturalReference(ref2);
76
        botName3.setNomenclaturalReference(ref3);
77
        zooName1.setPublicationYear(1823);
78

  
79
        List<TaxonBase<?>> list = new ArrayList<TaxonBase<?>>();
80

  
81
        Taxon taxon1 = Taxon.NewInstance(botName1, sec);
82
        Taxon taxon2 = Taxon.NewInstance(botName2, sec);
83
        Taxon taxon3 = Taxon.NewInstance(botName3, sec);
84
        Taxon zooTaxon4 = Taxon.NewInstance(zooName1, sec);
85

  
86
        taxon1.setId(1);
87
        taxon2.setId(2);
88
        taxon3.setId(3);
89
        zooTaxon4.setId(4);
90

  
91
        list.add(taxon3);
92
        list.add(taxon2);
93
        list.add(taxon1);
94
        list.add(zooTaxon4);
95
        Collections.sort(list, new TaxonComparator());
96

  
97
        //Order should be
98
//        4: 1823
99
//        3: 1943
100
//        1: 1945
101
//        2:
102
        Assert.assertEquals(list.get(0).getId(), 4);
103
        Assert.assertEquals(getYear(list.get(0)), "1823");
104
        Assert.assertEquals(list.get(1).getId(), 3);
105
        Assert.assertEquals(getYear(list.get(1)), "1943");
106
        Assert.assertEquals(list.get(2).getId(), 1);
107
        Assert.assertEquals(getYear(list.get(2)), "1945");
108
        Assert.assertEquals(list.get(3).getId(), 2);
109
        Assert.assertEquals(getYear(list.get(3)), "");
110

  
111

  
112
    }
113

  
114

  
115
    /**
116
     * @param taxonBase
117
     * @return
118
     */
119
    private String getYear(TaxonBase<?> taxon) {
120
        String year = "";
121
        TaxonNameBase<?,?> tnb = taxon.getName();
122
        if (tnb instanceof ZoologicalName){
123
            year = String.valueOf(((ZoologicalName)tnb).getPublicationYear());
124
        }else{
125
            year = tnb.getNomenclaturalReference().getYear();
126
        }
127
        return year;
128
    }
129
}

Also available in: Unified diff