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