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 */
021package org.biojava.bio.taxa;
022
023import org.biojava.bio.Annotatable;
024import org.biojava.bio.Annotation;
025import org.biojava.bio.SmallAnnotation;
026import org.biojava.utils.AbstractChangeable;
027import org.biojava.utils.ChangeEvent;
028import org.biojava.utils.ChangeForwarder;
029import org.biojava.utils.ChangeListener;
030import org.biojava.utils.ChangeSupport;
031import org.biojava.utils.ChangeType;
032import org.biojava.utils.ChangeVetoException;
033
034/**
035 * <p>An abstract implementation of Taxon.</p>
036 *
037 * <p>It is left up to the impementor to provide methods for accessing the
038 * parent and children. All other state is provided for here. A common pattern
039 * would be to route any Taxon.getParent() call back via a method on the
040 * TaxonFactory used to generate this instance.</p>
041 *
042 * @author Matthew Pocock
043 * @author Keith James
044 * @since 1.3
045 * @deprecated replaced by classes in {@link org.biojavax.bio.taxa org.biojavax.bio.taxa}
046 */
047public abstract class AbstractTaxon
048  extends
049    AbstractChangeable
050  implements
051    Taxon
052{
053  private transient ChangeListener annotationForwarder;
054  private Annotation ann;
055  private String commonName;
056  private String scientificName;
057  
058  protected AbstractTaxon() {}
059
060  protected AbstractTaxon(String scientificName, String commonName) {
061    this.scientificName = scientificName;
062    this.commonName = commonName;
063  }
064  
065  // ensure that change support gubbins gets wired in for the annotation object.
066  protected ChangeSupport getChangeSupport(ChangeType ct) {
067    ChangeSupport cs = super.getChangeSupport(ct);
068    
069    if(
070      (annotationForwarder == null) &&
071      (ct == null || ct == Annotatable.ANNOTATION)
072    ) {
073      annotationForwarder =
074              new ChangeForwarder.Retyper(this, cs, Annotation.PROPERTY);
075      getAnnotation().addChangeListener(
076        annotationForwarder,
077        Annotatable.ANNOTATION
078      );
079    }
080    
081    return cs;
082  }
083  
084  public String getCommonName() {
085    return commonName;
086  }
087  
088  public void setCommonName(String commonName)
089    throws
090      ChangeVetoException
091  {
092    if(this.commonName != null) {
093      throw new ChangeVetoException(
094        "Common name already set to: " +
095        this.commonName +
096        " so you can't set it to: " +
097        commonName
098      );
099    }
100    
101    if(hasListeners()) {
102      ChangeSupport cs = getChangeSupport(Taxon.CHANGE_COMMON_NAME);
103      ChangeEvent cevt = new ChangeEvent(this, Taxon.CHANGE_COMMON_NAME, commonName);
104      synchronized(cs) {
105        cs.firePreChangeEvent(cevt);
106        this.commonName = commonName;
107        cs.firePostChangeEvent(cevt);
108      }
109    } else {
110      this.commonName = commonName;
111    }
112  }
113  
114  public String getScientificName() {
115    return scientificName;
116  }
117  
118  public void setScientificName(String scientificName)
119    throws
120      ChangeVetoException
121  {
122    if(this.scientificName != null) {
123      throw new ChangeVetoException(
124        "Common name already set to: " +
125        this.scientificName +
126        " so you can't set it to: " +
127        scientificName
128      );
129    }
130    
131    if(hasListeners()) {
132      ChangeSupport cs = getChangeSupport(Taxon.CHANGE_SCIENTIFIC_NAME);
133      ChangeEvent cevt = new ChangeEvent(this, Taxon.CHANGE_SCIENTIFIC_NAME, scientificName);
134      synchronized(cs) {
135        cs.firePreChangeEvent(cevt);
136        this.scientificName = scientificName;
137        cs.firePostChangeEvent(cevt);
138      }
139    } else {
140      this.scientificName = scientificName;
141    }
142  }
143  
144  public Annotation getAnnotation() {
145    if(ann == null) {
146      ann = new SmallAnnotation();
147    }
148    
149    return ann;
150  }
151  
152  public boolean equals(Object o) {
153    if(o instanceof Taxon) {
154      Taxon t = (Taxon) o;
155      
156      return
157        this == t || (
158        safeEq(this.getScientificName(), t.getScientificName()) &&
159        safeEq(this.getCommonName(), t.getCommonName()) &&
160        safeEq(this.getChildren(), t.getChildren())
161        );
162    }
163    
164    return false;
165  }
166  
167  public String toString() {
168    Taxon parent = getParent();
169    String scientificName = getScientificName();
170    
171    if(parent != null) {
172      return parent.toString() + " -> " + scientificName;
173    } else {
174      return scientificName;
175    }
176  }
177  
178  public int hashCode() {
179    return getScientificName().hashCode();
180  }
181  
182  private boolean safeEq(Object a, Object b) {
183    if(a == null && b == null) {
184      return true;
185    } else if(a == null || b == null) {
186      return false;
187    } else {
188      return a.equals(b);
189    }
190  }
191}
192