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.util.HashMap;
025import java.util.HashSet;
026import java.util.Iterator;
027import java.util.Map;
028import java.util.Set;
029
030import org.biojava.utils.ObjectUtil;
031
032/**
033 * This class is an implementation of interface SequenceDBInstallation
034 * that manages a set of SequenceDB objects. The set of SequenceDB
035 * objects is initially empty and can be expanded by the user through
036 * the addSequenceDB() method. This SequenceDBInstallation is then
037 * able to serve the SequenceDB objects in this set.
038 *
039 * @author Keith James
040 * @author <a href="mailto:Gerald.Loeffler@vienna.at">Gerald
041 * Loeffler</a> (primary author) for the <a//href=
042 * "http://www.imp.univie.ac.at">IMP</a>
043 */
044public class SimpleSequenceDBInstallation implements SequenceDBInstallation
045{
046    private Map sequenceDBByIdentifier = new HashMap();
047
048    /**
049     * create an initially empty SimpleSequenceDBInstallation
050     */
051    public SimpleSequenceDBInstallation() { }
052
053  /**
054   * This method creates a new (and empty) HashSequenceDB with the
055   * given name that will be accessible through this sequence db
056   * installation through this name and all given other identifiers.
057   * @param name the name of the SequenceDB to create. Not null. If
058   * this name is already used by this sequence db installation, an
059   * IllegalArgumentException is thrown.
060   * @param otherIdentifiers a set of String objects that also serve
061   * as identifiers for the newly created SequenceDB object. This set
062   * should not contain the name of the SequenceDB, but if if does, it
063   * is just ignored because the name is an identifier by
064   * definition. The parameter may be empty or the empty set, in which
065   * case the name is the only identifier for the newly created
066   * SequenceDB. If any of the given identifiers (including the name)
067   * is already used by this SimpleSequenceDBInstallation, an
068   * IllegalArgumentException is thrown.
069   */
070    public synchronized void addSequenceDB(String name, Set otherIdentifiers)
071    {
072        if (name == null) {
073            throw new IllegalArgumentException("name was null");
074        }
075        // otherIdentifiers may only contain String objects - but this is checked later
076
077        // create set of all identifiers for the to-be-created SequenceDB
078        Set allIdentifiers = new HashSet();
079        allIdentifiers.add(name);
080        if (otherIdentifiers != null) allIdentifiers.addAll(otherIdentifiers);
081
082        // none of the identifiers may already be in use
083        Set currentIdentifiers = this.sequenceDBByIdentifier.keySet();
084        for (Iterator i = allIdentifiers.iterator(); i.hasNext();)
085        {
086            Object o = i.next();
087            if (! (o instanceof String)) {
088                throw new IllegalArgumentException("otherIdentifiers must be a Set of String objects");
089            }
090            if (currentIdentifiers.contains(o)) {
091                throw new IllegalArgumentException("name and otherIdentifiers must not already be in use");
092            }
093        }
094
095        // create new HashSequenceDB and at it to the map under all its identifiers
096        SequenceDB db = new HashSequenceDB(name);
097        for (Iterator i = allIdentifiers.iterator(); i.hasNext();)
098        {
099            String identifier = (String) i.next();
100            this.sequenceDBByIdentifier.put(identifier, db);
101        }
102    }
103
104    /**
105     * <code>addSequenceDB</code> adds a new SequenceDB which will be
106     * accessible via the name returned by its getName() method and
107     * via all other given identifiers.
108     *
109     * @param sequenceDB a <code>SequenceDB</code> object to
110     * add. Although a SequenceDB may normally have a null name this
111     * is not acceptable when it is added to a
112     * SimpleSequenceDBInstallation as the name is used as its primary
113     * identifier. If the name is already used by this
114     * SimpleSequenceDBInstallation, an IllegalArgumentException is
115     * thrown.
116     * @param otherIdentifiers a <code>Set</code> of String objects
117     * that also serve as identifiers for the newly created
118     * SequenceDB. This set should not contain the name of the
119     * SequenceDB, but if if does, it is just ignored because the name
120     * is an identifier by definition. The parameter may be empty or
121     * the empty set, in which case the name is the only identifier
122     * for the newly created SequenceDB. If any of the given
123     * identifiers (including the name) is already used by this
124     * sequence db installation, an IllegalArgumentException is
125     * thrown.
126     */
127    public synchronized void addSequenceDB(SequenceDBLite sequenceDB,
128                                           Set            otherIdentifiers)
129    {
130        if (sequenceDB == null) {
131            throw new IllegalArgumentException("SequenceDB was null");
132        }
133
134        // The SequenceDB name may not be null
135        String name = sequenceDB.getName();
136
137        // Create set of all identifiers for the to-be-added SequenceDB
138        Set allIdentifiers = new HashSet();
139        allIdentifiers.add(name);
140        if (otherIdentifiers != null) allIdentifiers.addAll(otherIdentifiers);
141
142        // None of the identifiers may already be in use
143        Set currentIdentifiers = this.sequenceDBByIdentifier.keySet();
144        for (Iterator i = allIdentifiers.iterator(); i.hasNext();)
145        {
146            Object o = i.next();
147            if (! (o instanceof String)) {
148                throw new IllegalArgumentException("otherIdentifiers must be a set of String objects");
149            }
150            if (currentIdentifiers.contains(o)) {
151                throw new IllegalArgumentException("name and otherIdentifiers must not already be in use");
152            }
153        }
154
155        // Add the SequenceDB to the map under all its identifiers
156        for (Iterator i = allIdentifiers.iterator(); i.hasNext();)
157        {
158            String identifier = (String) i.next();
159            this.sequenceDBByIdentifier.put(identifier, sequenceDB);
160        }
161    }
162
163  /**
164   * Return a newly created set of the SequenceDB objects that were
165   * already created through method addSequenceDB(). This set itself
166   * is not part of the state of this object (i.e. modifying the set
167   * does not modify this object) but the SequenceDB objects contained
168   * in the set are the same objects managed by this object.
169   */
170    public synchronized Set getSequenceDBs()
171    {
172        Set allDBs = new HashSet();
173        allDBs.addAll(this.sequenceDBByIdentifier.values());
174
175        return allDBs;
176    }
177
178  /**
179   * If the given identifier is known to this sequence db installation
180   * because it has been used in a call to addSequenceDB(), then this
181   * method returns the SequenceDB associated with this
182   * identifier. Otherwise, null is returned.
183   */
184    public synchronized SequenceDBLite getSequenceDB(String identifier)
185    {
186        if (identifier == null) {
187            throw new IllegalArgumentException("identifier was null");
188        }
189
190        return (SequenceDBLite) this.sequenceDBByIdentifier.get(identifier);
191    }
192
193    public String toString()
194    {
195        return "SimpleSequenceDBInstallation: "
196            + this.sequenceDBByIdentifier.values();
197    }
198
199    public synchronized boolean equals(Object o)
200    {
201        if (o == this) return true;
202
203        // if this class is a direct sub-class of Object:
204        if (o == null) return false;
205        if (! o.getClass().equals(this.getClass())) return false;
206
207        SimpleSequenceDBInstallation that = (SimpleSequenceDBInstallation) o;
208
209        // only compare fields of this class (not of super-classes):
210        if (! ObjectUtil.equals(this.sequenceDBByIdentifier,
211                                that.sequenceDBByIdentifier)) return false;
212
213        // this and that are identical if we made it 'til here
214        return true;
215    }
216
217    public synchronized int hashCode()
218    {
219        // if this class is a direct sub-class of Object:
220        int hc = 0;
221
222        // only take into account fields of this class (not of super-class):
223        hc = ObjectUtil.hashCode(hc, sequenceDBByIdentifier);
224
225        return hc;
226    }
227
228    /**
229     * Test this class
230     */
231    public static void main(String[] args)
232    {
233        System.out.println("Create sequence db installation");
234        SimpleSequenceDBInstallation dbInst = new SimpleSequenceDBInstallation();
235        System.out.println("Sequence db installation serves " + dbInst.getSequenceDBs().size() + " sequence dbs");
236        System.out.println("add swissprot (aka sprot, sp) and genbank (aka gb) do sequence db installation");
237        Set swissprotIDs = new HashSet();
238        swissprotIDs.add("sprot");
239        swissprotIDs.add("sp");
240        dbInst.addSequenceDB("swissprot", swissprotIDs);
241        Set genbankIDs = new HashSet();
242        genbankIDs.add("gb");
243        genbankIDs.add("genbank"); // this is not correct but should be ignored
244        dbInst.addSequenceDB("genbank", genbankIDs);
245        System.out.println("Sequence db installation serves " + dbInst.getSequenceDBs().size() + " sequence dbs");
246        System.out.println("Sequence db associated with identifier \"sprot\" is: " + dbInst.getSequenceDB("sprot"));
247        System.out.println("Sequence db associated with identifier \"swissprot\" is: " + dbInst.getSequenceDB("swissprot"));
248        System.out.println("Sequence db associated with identifier \"sp\" is: " + dbInst.getSequenceDB("sp"));
249        System.out.println("Sequence db associated with identifier \"willi\" is: " + dbInst.getSequenceDB("willi"));
250        System.out.println("Sequence db associated with identifier \"gb\" is: " + dbInst.getSequenceDB("gb"));
251        System.out.println("Sequence db associated with identifier \"genbank\" is: " + dbInst.getSequenceDB("genbank"));
252        System.out.println("Sequence db associated with identifier \"genebank\" is: " + dbInst.getSequenceDB("genebank"));
253    }
254}