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.biojava.bio.seq.db;
023
024import java.io.Serializable;
025import java.util.LinkedHashMap;
026import java.util.Iterator;
027import java.util.Map;
028import java.util.Set;
029
030import org.biojava.bio.BioException;
031import org.biojava.bio.seq.Sequence;
032import org.biojava.bio.seq.SequenceIterator;
033import org.biojava.utils.ChangeEvent;
034import org.biojava.utils.ChangeSupport;
035import org.biojava.utils.ChangeVetoException;
036
037/**
038 * An implementation of SequenceDB that uses an underlying HashMap to store the
039 * sequence objects.
040 *
041 * @author Matthew Pocock
042 * @author <A href="mailto:Gerald.Loeffler@vienna.at">Gerald Loeffler</A>
043 * @author Matias Pilpari (LinkedHashMap)
044 */
045public class HashSequenceDB
046  extends
047    AbstractSequenceDB
048  implements
049    SequenceDB,
050    Serializable {
051  /**
052   * The sequence-by-id map.
053   */
054  final private Map sequenceByID;
055  
056  /**
057   * An object to extract an ID for a sequence.
058   */
059  final private org.biojava.bio.seq.db.IDMaker idMaker;
060
061  /** 
062   * The name of this sequence database.
063   */
064  private String name;
065  
066  public String getName() {
067    return name;
068  }
069
070  public Sequence getSequence(String id) 
071      throws IllegalIDException
072  {
073      Sequence seq = (Sequence) sequenceByID.get(id);
074      if (seq == null) {
075          throw new IllegalIDException("Sequence with ID " + id + " could not be found");
076      }
077      return seq;
078  }
079
080  public Set ids() {
081    return sequenceByID.keySet();
082  }
083
084  public SequenceIterator sequenceIterator() {
085    return new SequenceIterator() {
086      Iterator seqI = sequenceByID.values().iterator();
087      public boolean hasNext() { return seqI.hasNext(); }
088      public Sequence nextSequence() { return (Sequence) seqI.next(); }
089    };
090  }
091
092  /**
093   * Add a sequence under a particular id.
094   *
095   * @param id  the id to use
096   * @param seq the Sequence to add
097   * @throws ChangeVetoException if this addition was vetoed
098   */
099  public void addSequence(String id, Sequence seq)
100  throws ChangeVetoException {
101    if(!hasListeners()) {
102      sequenceByID.put(id, seq);
103    } else {
104      ChangeSupport changeSupport = getChangeSupport(SequenceDB.SEQUENCES);
105      synchronized(changeSupport) {
106        ChangeEvent ce = new ChangeEvent(
107          this,
108          SequenceDB.SEQUENCES,
109          new Object[] { id, seq },
110          null
111        );
112        changeSupport.firePreChangeEvent(ce);
113        sequenceByID.put(id, seq);
114        changeSupport.firePostChangeEvent(ce);
115      }
116    }
117  }
118
119  /**
120   * Retrieve the IDMaker associated with this database.
121   *
122   * @return the current IDMaker object
123   */
124  public org.biojava.bio.seq.db.IDMaker getIDMaker() {
125    return idMaker;
126  }
127  
128  public void addSequence(Sequence seq)
129  throws ChangeVetoException {
130    String id = idMaker.calcID(seq);
131    if(!hasListeners()) {
132      addSequence(id, seq);
133    } else {
134      ChangeSupport changeSupport = getChangeSupport(SequenceDB.SEQUENCES);
135      synchronized(changeSupport) {
136        ChangeEvent ce = new ChangeEvent(
137          this,
138          SequenceDB.SEQUENCES,
139          id,
140          null
141        );
142        changeSupport.firePreChangeEvent(ce);
143        sequenceByID.remove(id);
144        changeSupport.firePostChangeEvent(ce);
145      }
146    }
147  }
148  
149  public void removeSequence(String id)
150  throws BioException, ChangeVetoException {
151    if(!hasListeners()) {
152      sequenceByID.remove(id);
153    } else {
154      ChangeSupport changeSupport = getChangeSupport(SequenceDB.SEQUENCES);
155      synchronized(changeSupport) {
156        ChangeEvent ce = new ChangeEvent(
157          this,
158          SequenceDB.SEQUENCES,
159          null,
160          id
161        );
162        changeSupport.firePreChangeEvent(ce);
163        sequenceByID.remove(id);
164        changeSupport.firePostChangeEvent(ce);
165      }
166    }
167  }
168
169  /**
170   * Generate a HashSequenceDB object that will use byName to generate ids for
171   * sequences and have a null name.
172   */
173  public HashSequenceDB() {
174    this(IDMaker.byName, null);
175  }
176  
177  /**
178   * Generate a HashSequenceDB object that will use idMaker to generate ids for
179   * sequences and have a null name.
180   *
181   * @param idMaker the object that will work out the default id for a sequence
182   */
183  public HashSequenceDB(org.biojava.bio.seq.db.IDMaker idMaker) {
184    this(idMaker, null);
185  }
186  
187  /**
188   * Generate a HashSequenceDB object that will use byName to generate ids and
189   * will have the requested name.
190   *
191   * @param name the name for this database
192   */
193  public HashSequenceDB(String name) {
194    this(IDMaker.byName, name);
195  }
196  
197  /**
198   * Generate a HashSequenceDB object that will use idMaker to generate ids for
199   * sequences and have the requested name.
200   *
201   * @param idMaker the object that will work out the default id for a sequence
202   * @param name the name for this database
203   */
204  public HashSequenceDB(org.biojava.bio.seq.db.IDMaker idMaker, String name) {
205    this.idMaker = idMaker;
206    this.name = name;
207    this.sequenceByID = new LinkedHashMap();
208  }
209}