- no change (just updated "last edited" for svn)
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / OrderedTermBase.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.common;
11
12 import javax.persistence.Entity;
13 import javax.persistence.Transient;
14 import javax.xml.bind.annotation.XmlAccessType;
15 import javax.xml.bind.annotation.XmlAccessorType;
16 import javax.xml.bind.annotation.XmlElement;
17 import javax.xml.bind.annotation.XmlSeeAlso;
18 import javax.xml.bind.annotation.XmlType;
19
20 import org.apache.log4j.Logger;
21 import org.hibernate.envers.Audited;
22 import org.hibernate.search.annotations.Indexed;
23
24 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTermBase;
25 import eu.etaxonomy.cdm.model.description.State;
26 import eu.etaxonomy.cdm.model.location.NamedArea;
27 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
28 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
29 import eu.etaxonomy.cdm.model.name.Rank;
30
31 /**
32 * @author m.doering
33 * @created 08-Nov-2007 13:06:23
34 */
35 @XmlAccessorType(XmlAccessType.FIELD)
36 @XmlType(name = "OrderedTermBase", propOrder = {
37 "orderIndex"
38 })
39 @XmlSeeAlso({
40 RelationshipTermBase.class,
41 PresenceAbsenceTermBase.class,
42 State.class,
43 NamedArea.class,
44 NamedAreaLevel.class,
45 NomenclaturalStatusType.class,
46 Rank.class
47 })
48 @Entity
49 @Indexed(index = "eu.etaxonomy.cdm.model.common.DefinedTermBase")
50 @Audited
51 public abstract class OrderedTermBase<T extends OrderedTermBase<?>> extends DefinedTermBase<T> implements Comparable<T> {
52 private static final long serialVersionUID = 8000797926720467399L;
53 @SuppressWarnings("unused")
54 private static final Logger logger = Logger.getLogger(OrderedTermBase.class);
55
56 //Order index, value < 1 means that this Term is not in order yet
57 @XmlElement(name = "OrderIndex")
58 protected int orderIndex;
59
60 /**
61 * Higher ordered terms have a lower order index,
62 * lower ordered terms have a higher order index:
63 * <p>
64 * <b>a.oderIndex &lt; b.oderIndex : a &gt; b</b>
65 * @return the order index of a term
66 */
67 public int getOrderIndex() {
68 return orderIndex;
69 }
70
71 // *********************** CONSTRUCTOR *************************/
72
73 //for JAXB only, TODO needed?
74 @Deprecated
75 protected OrderedTermBase(){}
76
77 protected OrderedTermBase(TermType type) {
78 super(type);
79 }
80 public OrderedTermBase(TermType type, String term, String label, String labelAbbrev) {
81 super(type, term, label, labelAbbrev);
82 }
83
84 // **************************** METHODS ******************************/
85
86 /**
87 * Compares this OrderedTermBase with the specified OrderedTermBase for
88 * order. Returns a -1, 0, or +1 if the orderIndex of this object is greater
89 * than, equal to, or less than the specified object. In case the parameter
90 * is <code>null</code> the
91 * <p>
92 * <b>Note:</b> The compare logic of this method might appear to be <b>inverse</b>
93 * to the one mentioned in
94 * {@link java.lang.Comparable#compareTo(java.lang.Object)}. This is, because the logic here
95 * is that the lower the orderIndex the higher the term. E.g. the very high {@link Rank}
96 * Kingdom may have an orderIndex close to 1.
97 *
98 * @param orderedTerm
99 * the OrderedTermBase to be compared
100 * @throws NullPointerException
101 * if the specified object is null
102 */
103 @Override
104 public int compareTo(T orderedTerm) {
105 return performCompareTo(orderedTerm, false);
106 }
107
108 /**
109 * Compares this OrderedTermBase with the specified OrderedTermBase for
110 * order. Returns a -1, 0, or +1 if the orderId of this object is greater
111 * than, equal to, or less than the specified object.
112 * <p>
113 * <b>Note:</b> The compare logic of this method is the <b>inverse logic</b>
114 * of the the one implemented in
115 * {@link java.lang.Comparable#compareTo(java.lang.Object)}
116 *
117 * @param orderedTerm
118 * the OrderedTermBase to be compared
119 * @param skipVocabularyCheck
120 * whether to skip checking if both terms to compare are in the
121 * same vocabulary
122 * @throws NullPointerException
123 * if the specified object is null
124 */
125 protected int performCompareTo(T orderedTerm, boolean skipVocabularyCheck) {
126
127 OrderedTermBase<?> orderedTermLocal = CdmBase.deproxy(orderedTerm, OrderedTermBase.class);
128 if(!skipVocabularyCheck){
129 if (this.vocabulary == null || orderedTermLocal.vocabulary == null){
130 throw new IllegalStateException("An ordered term (" + this.toString() + " or " + orderedTermLocal.toString() + ") of class " + this.getClass() + " or " + orderedTermLocal.getClass() + " does not belong to a vocabulary and therefore can not be compared");
131 }
132 if (! this.getVocabulary().getUuid().equals(orderedTermLocal.vocabulary.getUuid())){
133 throw new IllegalStateException("2 terms do not belong to the same vocabulary and therefore can not be compared: " + this.getTitleCache() + " and " + orderedTermLocal.getTitleCache());
134 }
135 }
136
137 int orderThat;
138 int orderThis;
139 try {
140 orderThat = orderedTermLocal.orderIndex;//OLD: this.getVocabulary().getTerms().indexOf(orderedTerm);
141 orderThis = orderIndex; //OLD: this.getVocabulary().getTerms().indexOf(this);
142 } catch (RuntimeException e) {
143 throw e;
144 }
145 if (orderThis > orderThat){
146 return -1;
147 }else if (orderThis < orderThat){
148 return 1;
149 }else {
150 return 0;
151 }
152 }
153
154 // public int compareTo(IdentifiableEntity o) {
155 // if (o instanceof OrderedTermBase){
156 // return compareTo((OrderedTermBase)o);
157 // }else{
158 // return super.compareTo(o);
159 // }
160 // }
161
162 /**
163 * If this term is lower than the parameter term, true is returned, else false.
164 * If the parameter term is null, an Exception is thrown.
165 * @param orderedTerm
166 * @return boolean result of the comparison
167 */
168 public boolean isLower(T orderedTerm){
169 return (this.compareTo(orderedTerm) < 0 );
170 }
171
172
173 /**
174 * If this term is higher than the parameter term, true is returned, else false.
175 * If the parameter term is null, an Exception is thrown.
176 * @param orderedTerm
177 * @return boolean result of the comparison
178 */
179 public boolean isHigher(T orderedTerm){
180 return (this.compareTo(orderedTerm) > 0 );
181 }
182
183
184 /**
185 * @deprecated To be used only by OrderedTermVocabulary
186 **/
187 @Deprecated
188 protected boolean decreaseIndex(OrderedTermVocabulary<T> vocabulary){
189 if (vocabulary.indexChangeAllowed(this) == true){
190 orderIndex--;
191 return true;
192 }else{
193 return false;
194 }
195 }
196
197 /**
198 * @deprecated To be used only by OrderedTermVocabulary
199 **/
200 @Deprecated
201 protected boolean incrementIndex(OrderedTermVocabulary<T> vocabulary){
202 if (vocabulary.indexChangeAllowed(this) == true){
203 orderIndex++;
204 return true;
205 }else{
206 return false;
207 }
208 }
209
210 @Override
211 public boolean equals(Object object){
212 if(this == object) {
213 return true;
214 }
215 if((object == null) || (!OrderedTermBase.class.isAssignableFrom(object.getClass()))) {
216 return false;
217 }else{
218 OrderedTermBase<?> orderedTermBase = (OrderedTermBase<?>)object;
219 if (orderedTermBase.getUuid().equals(this.getUuid())){
220 return true;
221 }else{
222 return false;
223 }
224 }
225 }
226
227 @Transient
228 public T getNextHigherTerm(){ //#3327
229 if (getVocabulary() == null){
230 return null;
231 }else{
232 @SuppressWarnings("unchecked")
233 OrderedTermBase<T> result = CdmBase.deproxy(getVocabulary(), OrderedTermVocabulary.class).getNextHigherTerm(this);
234 return (T)result;
235 }
236 }
237
238 @Transient
239 public T getNextLowerTerm(){ //#3327
240 if (getVocabulary() == null){
241 return null;
242 }else{
243 @SuppressWarnings("unchecked")
244 OrderedTermBase<T> result = CdmBase.deproxy(getVocabulary(), OrderedTermVocabulary.class).getNextLowerTerm(this);
245 return (T)result;
246 }
247 }
248
249 //*********************** CLONE ********************************************************/
250
251 /**
252 * Clones <i>this</i> OrderedTermBase. This is a shortcut that enables to create
253 * a new instance that differs only slightly from <i>this</i> OrderedTermBase.
254 *
255 * @see eu.etaxonomy.cdm.model.common.DefinedTermBase#clone()
256 * @see java.lang.Object#clone()
257 */
258 @Override
259 public Object clone() {
260 OrderedTermBase<?> result = (OrderedTermBase<?>) super.clone();
261 //no changes to orderIndex
262 return result;
263 }
264 }