Project

General

Profile

Download (9.38 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.model.term;
10

    
11
import java.util.UUID;
12

    
13
import javax.persistence.Entity;
14
import javax.persistence.Transient;
15
import javax.xml.bind.annotation.XmlAccessType;
16
import javax.xml.bind.annotation.XmlAccessorType;
17
import javax.xml.bind.annotation.XmlElement;
18
import javax.xml.bind.annotation.XmlSeeAlso;
19
import javax.xml.bind.annotation.XmlType;
20

    
21
import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
22
import org.hibernate.envers.Audited;
23

    
24
import eu.etaxonomy.cdm.common.CdmUtils;
25
import eu.etaxonomy.cdm.model.common.CdmBase;
26
import eu.etaxonomy.cdm.model.common.RelationshipTermBase;
27
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
28
import eu.etaxonomy.cdm.model.description.State;
29
import eu.etaxonomy.cdm.model.location.NamedArea;
30
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
31
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
32
import eu.etaxonomy.cdm.model.name.Rank;
33

    
34
/**
35
 * @author m.doering
36
 * @since 08-Nov-2007 13:06:23
37
 */
38
@XmlAccessorType(XmlAccessType.FIELD)
39
@XmlType(name = "OrderedTermBase", propOrder = {
40
    "orderIndex"
41
})
42
@XmlSeeAlso({
43
    RelationshipTermBase.class,
44
    PresenceAbsenceTerm.class,
45
    State.class,
46
    NamedArea.class,
47
    NamedAreaLevel.class,
48
    NomenclaturalStatusType.class,
49
    Rank.class
50
})
51
@Entity
52
@Audited
53
public abstract class OrderedTermBase<T extends OrderedTermBase<T>>
54
        extends DefinedTermBase<T> {
55

    
56
    private static final long serialVersionUID = 8000797926720467399L;
57
    @SuppressWarnings("unused")
58
    private static final Logger logger = LogManager.getLogger(OrderedTermBase.class);
59

    
60
    //Order index, value < 1 means that this Term is not in order yet
61
    @XmlElement(name = "OrderIndex")
62
    protected int orderIndex;
63

    
64
    /**
65
     * Higher ordered terms have a lower order index,
66
     * lower ordered terms have a higher order index:
67
     * <p>
68
     * <b>a.oderIndex &lt; b.oderIndex : a &gt; b</b>
69
     * @return the order index of a term
70
     */
71
    public int getOrderIndex() {
72
        return orderIndex;
73
    }
74

    
75
// *********************** CONSTRUCTOR *************************/
76

    
77
    //for JAXB only, TODO needed?
78
    @Deprecated
79
    protected OrderedTermBase(){}
80

    
81
    protected OrderedTermBase(TermType type) {
82
        super(type);
83
    }
84
    public OrderedTermBase(TermType type, String description, String label, String labelAbbrev) {
85
        super(type, description, label, labelAbbrev);
86
    }
87

    
88
// **************************** METHODS ******************************/
89

    
90
    /**
91
     * Compares this OrderedTermBase with the specified OrderedTermBase for
92
     * order. Returns a -1, 0, or +1 if the orderIndex of this object is greater
93
     * than, equal to, or less than the specified object. In case the parameter
94
     * is <code>null</code> the
95
     * <p>
96
     * <b>Note:</b> The compare logic of this method might appear to be <b>inverse</b>
97
     * to the one mentioned in
98
     * {@link java.lang.Comparable#compareTo(java.lang.Object)}. This is, because the logic here
99
     * is that the lower the orderIndex the higher the term. E.g. the very high {@link Rank}
100
     * Kingdom may have an orderIndex close to 1.
101
     *
102
     * @param orderedTerm
103
     *            the OrderedTermBase to be compared
104
     * @throws NullPointerException
105
     *             if the specified object is null
106
     */
107
    @Override
108
    public int compareTo(T orderedTerm) {
109
        return performCompareTo(orderedTerm, false);
110
    }
111

    
112
    /**
113
     * Compares this {@link OrderedTermBase ordered term} with the given {@link OrderedTermBase thatTerm} for
114
     * order.  Returns a -1, 0, or +1 if the orderId of this object is greater
115
     * than, equal to, or less than the specified object.
116
     * <p>
117
     * <b>Note:</b> The compare logic of this method is the <b>inverse logic</b>
118
     * of the the one implemented in
119
     * {@link java.lang.Comparable#compareTo(java.lang.Object)}
120
     *
121
     * @param orderedTerm
122
     *            the OrderedTermBase to be compared
123
     * @param skipVocabularyCheck
124
     *            whether to skip checking if both terms to compare are in the
125
     *            same vocabulary
126
     * @throws NullPointerException
127
     *             if the specified object is null
128
     */
129
    protected int performCompareTo(T thatTerm , boolean skipVocabularyCheck ) {
130

    
131
    	T thatTermLocal = CdmBase.deproxy(thatTerm);
132
    	if(!skipVocabularyCheck){
133
            if (this.vocabulary == null || thatTermLocal.vocabulary == null){
134
                throw new IllegalStateException("An ordered term (" + this.toString() + " or " + thatTermLocal.toString() + ") of class " + this.getClass() + " or " + thatTermLocal.getClass() + " does not belong to a vocabulary and therefore can not be compared");
135
            }
136
            if (! this.getVocabulary().getUuid().equals(thatTermLocal.vocabulary.getUuid())){
137
               throw new IllegalStateException("2 terms do not belong to the same vocabulary and therefore can not be compared: " + this.getTitleCache() + " and " + thatTermLocal.getTitleCache());
138
            }
139
        }
140

    
141
    	int vocCompare = compareVocabularies(thatTermLocal);
142
        if (vocCompare != 0){
143
            return vocCompare;
144
        }
145

    
146
        int orderThat;
147
        int orderThis;
148
        try {
149
            orderThat = thatTermLocal.orderIndex;
150
            orderThis = orderIndex;
151
        } catch (RuntimeException e) {
152
            throw e;
153
        }
154
        if (orderThis > orderThat){
155
            return -1;
156
        }else if (orderThis < orderThat){
157
            return 1;
158
        }else {
159
            if (skipVocabularyCheck){
160
                String errorStr = "The term %s (ID: %s) is not attached to any vocabulary. This should not happen. "
161
                        + "Please add the term to an vocabulary";
162
                if (this.vocabulary == null){
163
                    throw new IllegalStateException(String.format(errorStr, this.getLabel(), String.valueOf(this.getId())));
164
                }else if (thatTermLocal.vocabulary == null){
165
                    throw new IllegalStateException(String.format(errorStr, thatTermLocal.getLabel(), String.valueOf(thatTermLocal.getId())));
166
                }
167
            }
168
            return 0;
169
        }
170
    }
171

    
172
    protected int compareVocabularies(T thatTerm) {
173
        //if vocabularies are not equal order by voc.uuid to get a defined behavior
174
        //ordering terms from 2 different vocabularies is generally not recommended
175
        UUID thisVocUuid = this.vocabulary == null? null:this.vocabulary.getUuid();
176
        UUID thatVocUuid = thatTerm.getVocabulary() == null? null:thatTerm.getVocabulary().getUuid();
177
        int vocCompare = CdmUtils.nullSafeCompareTo(thisVocUuid, thatVocUuid);
178
        return vocCompare;
179
    }
180

    
181
    /**
182
     * If this term is lower than the parameter term, true is returned, else false.
183
     * If the parameter term is null, an Exception is thrown.
184
     * @param orderedTerm
185
     * @return boolean result of the comparison
186
     */
187
    public boolean isLower(T orderedTerm){
188
        return (this.compareTo(orderedTerm) < 0 );
189
    }
190

    
191
    /**
192
     * If this term is higher than the parameter term, true is returned, else false.
193
     * If the parameter term is null, an Exception is thrown.
194
     * @param orderedTerm
195
     * @return boolean result of the comparison
196
     */
197
    public boolean isHigher(T orderedTerm){
198
        return (this.compareTo(orderedTerm) > 0 );
199
    }
200

    
201
    /**
202
     * @deprecated To be used only by OrderedTermVocabulary
203
     **/
204
    @Deprecated
205
    protected boolean decreaseIndex(OrderedTermVocabulary vocabulary){
206
        if (vocabulary.indexChangeAllowed(this) == true){
207
            orderIndex--;
208
            return true;
209
        }else{
210
            return false;
211
        }
212
    }
213

    
214
    /**
215
     * @deprecated To be used only by OrderedTermVocabulary
216
     **/
217
    @Deprecated
218
    protected boolean incrementIndex(OrderedTermVocabulary vocabulary){
219
        if (vocabulary.indexChangeAllowed(this) == true){
220
            orderIndex++;
221
            return true;
222
        }else{
223
            return false;
224
        }
225
    }
226

    
227

    
228
    @SuppressWarnings("unchecked")
229
    @Transient
230
    public T getNextHigherTerm(){  //#3327
231
        if (getVocabulary() == null){
232
            return null;
233
        }else{
234
            OrderedTermBase<T> result = CdmBase.deproxy(getVocabulary(), OrderedTermVocabulary.class).getNextHigherTerm(this);
235
            return (T)result;
236
        }
237
    }
238

    
239
    @SuppressWarnings("unchecked")
240
    @Transient
241
    public T getNextLowerTerm(){ //#3327
242
        if (getVocabulary() == null){
243
            return null;
244
        }else{
245
            OrderedTermBase<T> result = CdmBase.deproxy(getVocabulary(), OrderedTermVocabulary.class).getNextLowerTerm(this);
246
            return (T)result;
247
        }
248
    }
249

    
250
//*********************** CLONE ********************************************************/
251

    
252
    /**
253
     * Clones <i>this</i> OrderedTermBase. This is a shortcut that enables to create
254
     * a new instance that differs only slightly from <i>this</i> OrderedTermBase.
255
     *
256
     * @see eu.etaxonomy.cdm.model.term.DefinedTermBase#clone()
257
     * @see java.lang.Object#clone()
258
     */
259
    @Override
260
    public OrderedTermBase<T> clone() {
261
        OrderedTermBase<T> result = (OrderedTermBase<T>) super.clone();
262
        //no changes to orderIndex
263
        return result;
264
    }
265
}
(15-15/30)