001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021 022package org.biojavax.ontology; 023 024import java.util.Arrays; 025import java.util.Set; 026import java.util.TreeSet; 027 028import org.biojava.bio.Annotation; 029import org.biojava.ontology.Ontology; 030import org.biojava.ontology.Term; 031import org.biojava.utils.AbstractChangeable; 032import org.biojava.utils.ChangeEvent; 033import org.biojava.utils.ChangeSupport; 034import org.biojava.utils.ChangeVetoException; 035import org.biojavax.RankedCrossRef; 036import org.biojavax.RichAnnotation; 037 038/** 039 * A Term object that can be compared and thus sorted. 040 * @author Richard Holland 041 * @since 1.5 042 */ 043public class SimpleComparableTerm extends AbstractChangeable implements ComparableTerm { 044 045 private String name; 046 private String description; 047 private ComparableOntology ontology; 048 private String identifier; 049 private Boolean obsolete; 050 private Set synonyms = new TreeSet(); 051 private Set rankedcrossrefs = new TreeSet(); 052 053 /** 054 * Creates a new instance of SimpleComparableTerm with synonyms. 055 * @param ontology The ontology to put the term in. Must not be null. 056 * @param name the name of the term. Must not be null. 057 * @param synonyms a set of synonyms for the term. Can be null. 058 */ 059 SimpleComparableTerm(ComparableOntology ontology, String name, Object[] synonyms) { 060 if (name == null || name.equals("")) throw new IllegalArgumentException("Name must not be null or empty"); 061 if (ontology == null) throw new IllegalArgumentException("Ontology must not be null"); 062 this.name = name; 063 this.description = null; 064 this.ontology = ontology; 065 this.identifier = null; 066 this.obsolete = Boolean.FALSE; 067 if (synonyms!=null 068 && synonyms.length != 0) this.synonyms.addAll(Arrays.asList(synonyms)); 069 } 070 071 // Hibernate requirement - not for public use. 072 protected SimpleComparableTerm() {} 073 074 /** 075 * {@inheritDoc} 076 */ 077 public int hashCode() { 078 int value = 17; 079 // Hibernate comparison - we haven't been populated yet 080 if (this.ontology==null) return value; 081 // Normal comparison 082 value = 37*value + this.name.hashCode(); 083 value = 37*value + this.ontology.hashCode(); 084 return value; 085 } 086 087 /** 088 * {@inheritDoc} 089 * Two terms are equal if they are in the same ontology and 090 * share the same name. 091 */ 092 public boolean equals(Object obj) { 093 if (obj == this) return true; 094 if (!(obj instanceof Term)) return false; 095 // Hibernate comparison - we haven't been populated yet 096 if (this.ontology==null) return false; 097 // Normal comparison 098 Term that = (Term) obj; 099 return this.ontology.equals(that.getOntology()) && 100 this.name.equals(that.getName()); 101 } 102 103 /** 104 * {@inheritDoc} 105 * Terms are sorted by ontology first, then name. 106 */ 107 public int compareTo(Object o) { 108 if (o==this) return 0; 109 // Hibernate comparison - we haven't been populated yet 110 if (this.ontology==null) return -1; 111 // Normal comparison 112 Term them = (Term)o; 113 if (!this.ontology.equals(them.getOntology())) return this.ontology.compareTo(them.getOntology()); 114 return this.name.compareTo(them.getName()); 115 } 116 117 /** 118 * {@inheritDoc} 119 * Synonyms are stored in the database as the results of a toString() operation 120 * on each synonym object. This doesn't happen until it reaches the database 121 * though, so if you are not using a database, don't worry about it. 122 */ 123 public void addSynonym(Object synonym) { this.synonyms.add(synonym); } 124 125 /** 126 * {@inheritDoc} 127 */ 128 public void removeSynonym(Object synonym) { this.synonyms.remove(synonym); } 129 130 /** 131 * {@inheritDoc} 132 */ 133 public Object[] getSynonyms() { return this.synonyms.toArray(); } 134 135 // Hibernate requirement - not for public use. 136 Set getSynonymSet() { return this.synonyms; } 137 138 // Hibernate requirement - not for public use. 139 void setSynonymSet(Set synonyms) { this.synonyms = synonyms; } 140 141 /** 142 * {@inheritDoc} 143 * <b>Warning</b> this method gives access to the original 144 * Collection not a copy. This is required by Hibernate. If you 145 * modify the object directly the behaviour may be unpredictable. 146 */ 147 public Set getRankedCrossRefs() { return this.rankedcrossrefs; } // original for Hibernate 148 149 /** 150 * {@inheritDoc} 151 * <b>Warning</b> this method gives access to the original 152 * Collection not a copy. This is required by Hibernate. If you 153 * modify the object directly the behaviour may be unpredictable. 154 */ 155 public void setRankedCrossRefs(Set rankedcrossrefs) throws ChangeVetoException { 156 this.rankedcrossrefs = rankedcrossrefs; // original for Hibernate 157 } 158 159 /** 160 * {@inheritDoc} 161 */ 162 public void addRankedCrossRef(RankedCrossRef crossref) throws ChangeVetoException { 163 if (crossref==null) throw new IllegalArgumentException("Crossref cannot be null"); 164 if(!this.hasListeners(ComparableTerm.RANKEDCROSSREF)) { 165 this.rankedcrossrefs.add(crossref); 166 } else { 167 ChangeEvent ce = new ChangeEvent( 168 this, 169 ComparableTerm.RANKEDCROSSREF, 170 crossref, 171 null 172 ); 173 ChangeSupport cs = this.getChangeSupport(ComparableTerm.RANKEDCROSSREF); 174 synchronized(cs) { 175 cs.firePreChangeEvent(ce); 176 this.rankedcrossrefs.add(crossref); 177 cs.firePostChangeEvent(ce); 178 } 179 } 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 public void removeRankedCrossRef(RankedCrossRef crossref) throws ChangeVetoException { 186 if (crossref==null) throw new IllegalArgumentException("Crossref cannot be null"); 187 if(!this.hasListeners(ComparableTerm.RANKEDCROSSREF)) { 188 this.rankedcrossrefs.remove(crossref); 189 } else { 190 ChangeEvent ce = new ChangeEvent( 191 this, 192 ComparableTerm.RANKEDCROSSREF, 193 null, 194 crossref 195 ); 196 ChangeSupport cs = this.getChangeSupport(ComparableTerm.RANKEDCROSSREF); 197 synchronized(cs) { 198 cs.firePreChangeEvent(ce); 199 this.rankedcrossrefs.remove(crossref); 200 cs.firePostChangeEvent(ce); 201 } 202 } 203 } 204 205 /** 206 * {@inheritDoc} 207 */ 208 public String getName() { return this.name; } 209 210 // Hibernate requirement - not for public use. 211 void setName(String name) { this.name = name; } 212 213 /** 214 * {@inheritDoc} 215 */ 216 public String getDescription() { return this.description; } 217 218 /** 219 * {@inheritDoc} 220 */ 221 public void setDescription(String description) throws ChangeVetoException { 222 if(!this.hasListeners(ComparableTerm.DESCRIPTION)) { 223 this.description = description; 224 } else { 225 ChangeEvent ce = new ChangeEvent( 226 this, 227 ComparableTerm.DESCRIPTION, 228 description, 229 this.description 230 ); 231 ChangeSupport cs = this.getChangeSupport(ComparableTerm.DESCRIPTION); 232 synchronized(cs) { 233 cs.firePreChangeEvent(ce); 234 this.description = description; 235 cs.firePostChangeEvent(ce); 236 } 237 } 238 } 239 240 /** 241 * {@inheritDoc} 242 */ 243 public Ontology getOntology() { return this.ontology; } 244 245 // Hibernate requirement - not for public use. 246 void setOntology(ComparableOntology ontology) { this.ontology = ontology; } 247 248 /** 249 * {@inheritDoc} 250 * Form: "ontology:name [obsolete]" where [obsolete] is optional 251 */ 252 public String toString() { 253 boolean isobs = (this.obsolete!=null && this.obsolete.booleanValue()); 254 return this.ontology+":"+this.name+(isobs?" [obsolete]":""); 255 } 256 257 /** 258 * {@inheritDoc} 259 * ALWAYS RETURNS AN EMPTY ANNOTATION OBJECT 260 */ 261 public Annotation getAnnotation() { return RichAnnotation.EMPTY_ANNOTATION; } 262 263 /** 264 * {@inheritDoc} 265 */ 266 public String getIdentifier() { return this.identifier; } 267 268 /** 269 * {@inheritDoc} 270 */ 271 public void setIdentifier(String identifier) throws ChangeVetoException { 272 if(!this.hasListeners(ComparableTerm.IDENTIFIER)) { 273 this.identifier = identifier; 274 } else { 275 ChangeEvent ce = new ChangeEvent( 276 this, 277 ComparableTerm.IDENTIFIER, 278 identifier, 279 this.identifier 280 ); 281 ChangeSupport cs = this.getChangeSupport(ComparableTerm.IDENTIFIER); 282 synchronized(cs) { 283 cs.firePreChangeEvent(ce); 284 this.identifier = identifier; 285 cs.firePostChangeEvent(ce); 286 } 287 } 288 } 289 290 // Hibernate requirement - not for public use. 291 String getObsoleteChar() { 292 return (this.getObsolete()!=null && this.getObsolete().equals(Boolean.TRUE))?"X":null; 293 } 294 295 // Hibernate requirement - not for public use. 296 void setObsoleteChar(String obsolete) throws ChangeVetoException { 297 this.setObsolete(Boolean.valueOf(obsolete!=null && obsolete.equals("X"))); 298 } 299 300 /** 301 * {@inheritDoc} 302 */ 303 public Boolean getObsolete() { return this.obsolete; } 304 305 /** 306 * {@inheritDoc} 307 */ 308 public void setObsolete(Boolean obsolete) throws ChangeVetoException { 309 if(!this.hasListeners(ComparableTerm.OBSOLETE)) { 310 this.obsolete = obsolete; 311 } else { 312 ChangeEvent ce = new ChangeEvent( 313 this, 314 ComparableTerm.OBSOLETE, 315 obsolete, 316 this.obsolete 317 ); 318 ChangeSupport cs = this.getChangeSupport(ComparableTerm.OBSOLETE); 319 synchronized(cs) { 320 cs.firePreChangeEvent(ce); 321 this.obsolete = obsolete; 322 cs.firePostChangeEvent(ce); 323 } 324 } 325 } 326 327 // Hibernate requirement - not for public use. 328 private Integer id; 329 330 /** 331 * Gets the Hibernate ID. Should be used with caution. 332 * @return the Hibernate ID, if using Hibernate. 333 */ 334 public Integer getId() { return this.id; } 335 336 /** 337 * Sets the Hibernate ID. Should be used with caution. 338 * @param id the Hibernate ID, if using Hibernate. 339 */ 340 public void setId(Integer id) { this.id = id;} 341}