2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.model
.term
;
11 import java
.util
.UUID
;
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
;
21 import org
.apache
.logging
.log4j
.LogManager
;
22 import org
.apache
.logging
.log4j
.Logger
;
23 import org
.hibernate
.envers
.Audited
;
25 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
26 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
27 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipTermBase
;
28 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTerm
;
29 import eu
.etaxonomy
.cdm
.model
.description
.State
;
30 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
31 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
32 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
33 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
37 * @since 08-Nov-2007 13:06:23
39 @XmlAccessorType(XmlAccessType
.FIELD
)
40 @XmlType(name
= "OrderedTermBase", propOrder
= {
44 RelationshipTermBase
.class,
45 PresenceAbsenceTerm
.class,
49 NomenclaturalStatusType
.class,
54 public abstract class OrderedTermBase
<T
extends OrderedTermBase
<T
>>
55 extends DefinedTermBase
<T
> {
57 private static final long serialVersionUID
= 8000797926720467399L;
58 @SuppressWarnings("unused")
59 private static final Logger logger
= LogManager
.getLogger(OrderedTermBase
.class);
61 //Order index, value < 1 means that this Term is not in order yet
62 @XmlElement(name
= "OrderIndex")
63 protected int orderIndex
;
66 * Higher ordered terms have a lower order index,
67 * lower ordered terms have a higher order index:
69 * <b>a.oderIndex < b.oderIndex : a > b</b>
70 * @return the order index of a term
72 public int getOrderIndex() {
76 // *********************** CONSTRUCTOR *************************/
78 //for hibernate use only, protected required by bytebuddy and subclasses outside package
80 protected OrderedTermBase(){}
82 protected OrderedTermBase(TermType type
) {
85 public OrderedTermBase(TermType type
, String description
, String label
, String labelAbbrev
) {
86 super(type
, description
, label
, labelAbbrev
);
89 // **************************** METHODS ******************************/
92 * Compares this OrderedTermBase with the specified OrderedTermBase for
93 * order. Returns a -1, 0, or +1 if the orderIndex of this object is greater
94 * than, equal to, or less than the specified object. In case the parameter
95 * is <code>null</code> the
97 * <b>Note:</b> The compare logic of this method might appear to be <b>inverse</b>
98 * to the one mentioned in
99 * {@link java.lang.Comparable#compareTo(java.lang.Object)}. This is, because the logic here
100 * is that the lower the orderIndex the higher the term. E.g. the very high {@link Rank}
101 * Kingdom may have an orderIndex close to 1.
104 * the OrderedTermBase to be compared
105 * @throws NullPointerException
106 * if the specified object is null
109 public int compareTo(T orderedTerm
) {
110 return performCompareTo(orderedTerm
, false);
114 * Compares this {@link OrderedTermBase ordered term} with the given {@link OrderedTermBase thatTerm} for
115 * order. Returns a -1, 0, or +1 if the orderId of this object is greater
116 * than, equal to, or less than the specified object.
118 * <b>Note:</b> The compare logic of this method is the <b>inverse logic</b>
119 * of the the one implemented in
120 * {@link java.lang.Comparable#compareTo(java.lang.Object)}
123 * the OrderedTermBase to be compared
124 * @param skipVocabularyCheck
125 * whether to skip checking if both terms to compare are in the
127 * @throws NullPointerException
128 * if the specified object is null
130 protected int performCompareTo(T thatTerm
, boolean skipVocabularyCheck
) {
132 T thatTermLocal
= CdmBase
.deproxy(thatTerm
);
133 if(!skipVocabularyCheck
){
134 if (this.vocabulary
== null || thatTermLocal
.vocabulary
== null){
135 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");
137 if (! this.getVocabulary().getUuid().equals(thatTermLocal
.vocabulary
.getUuid())){
138 throw new IllegalStateException("2 terms do not belong to the same vocabulary and therefore can not be compared: " + this.getTitleCache() + " and " + thatTermLocal
.getTitleCache());
142 int vocCompare
= compareVocabularies(thatTermLocal
);
143 if (vocCompare
!= 0){
150 orderThat
= thatTermLocal
.orderIndex
;
151 orderThis
= orderIndex
;
152 } catch (RuntimeException e
) {
155 if (orderThis
> orderThat
){
157 }else if (orderThis
< orderThat
){
160 if (skipVocabularyCheck
){
161 String errorStr
= "The term %s (ID: %s) is not attached to any vocabulary. This should not happen. "
162 + "Please add the term to an vocabulary";
163 if (this.vocabulary
== null){
164 throw new IllegalStateException(String
.format(errorStr
, this.getLabel(), String
.valueOf(this.getId())));
165 }else if (thatTermLocal
.vocabulary
== null){
166 throw new IllegalStateException(String
.format(errorStr
, thatTermLocal
.getLabel(), String
.valueOf(thatTermLocal
.getId())));
173 protected int compareVocabularies(T thatTerm
) {
174 //if vocabularies are not equal order by voc.uuid to get a defined behavior
175 //ordering terms from 2 different vocabularies is generally not recommended
176 UUID thisVocUuid
= this.vocabulary
== null?
null:this.vocabulary
.getUuid();
177 UUID thatVocUuid
= thatTerm
.getVocabulary() == null?
null:thatTerm
.getVocabulary().getUuid();
178 int vocCompare
= CdmUtils
.nullSafeCompareTo(thisVocUuid
, thatVocUuid
);
183 * If this term is lower than the parameter term, true is returned, else false.
184 * If the parameter term is null, an Exception is thrown.
186 * @return boolean result of the comparison
188 public boolean isLower(T orderedTerm
){
189 return (this.compareTo(orderedTerm
) < 0 );
193 * If this term is higher than the parameter term, true is returned, else false.
194 * If the parameter term is null, an Exception is thrown.
196 * @return boolean result of the comparison
198 public boolean isHigher(T orderedTerm
){
199 return (this.compareTo(orderedTerm
) > 0 );
203 * @deprecated To be used only by OrderedTermVocabulary
206 protected boolean decreaseIndex(OrderedTermVocabulary vocabulary
){
207 if (vocabulary
.indexChangeAllowed(this) == true){
216 * @deprecated To be used only by OrderedTermVocabulary
219 protected boolean incrementIndex(OrderedTermVocabulary vocabulary
){
220 if (vocabulary
.indexChangeAllowed(this) == true){
229 @SuppressWarnings("unchecked")
231 public T
getNextHigherTerm(){ //#3327
232 if (getVocabulary() == null){
235 OrderedTermBase
<T
> result
= CdmBase
.deproxy(getVocabulary(), OrderedTermVocabulary
.class).getNextHigherTerm(this);
240 @SuppressWarnings("unchecked")
242 public T
getNextLowerTerm(){ //#3327
243 if (getVocabulary() == null){
246 OrderedTermBase
<T
> result
= CdmBase
.deproxy(getVocabulary(), OrderedTermVocabulary
.class).getNextLowerTerm(this);
251 //*********************** CLONE ********************************************************/
254 * Clones <i>this</i> OrderedTermBase. This is a shortcut that enables to create
255 * a new instance that differs only slightly from <i>this</i> OrderedTermBase.
257 * @see eu.etaxonomy.cdm.model.term.DefinedTermBase#clone()
258 * @see java.lang.Object#clone()
261 public OrderedTermBase
<T
> clone() {
262 OrderedTermBase
<T
> result
= (OrderedTermBase
<T
>) super.clone();
263 //no changes to orderIndex