X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fws%2Fseqfetcher%2FASequenceFetcher.java;h=8f3f3b83bd2b1369fbc56b88c152bfe71842cf1a;hb=a1984b1c8c273ed33c7ce9283039f4027dcae2de;hp=8a8cf445571aba433882a710202331bc03c8cf63;hpb=506d60f0e188723ddc91c26824b41ac7034df3fe;p=jalview.git diff --git a/src/jalview/ws/seqfetcher/ASequenceFetcher.java b/src/jalview/ws/seqfetcher/ASequenceFetcher.java index 8a8cf44..8f3f3b8 100644 --- a/src/jalview/ws/seqfetcher/ASequenceFetcher.java +++ b/src/jalview/ws/seqfetcher/ASequenceFetcher.java @@ -1,300 +1,460 @@ -/* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4) - * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ -package jalview.ws.seqfetcher; - -import jalview.datamodel.AlignmentI; -import jalview.datamodel.SequenceI; - -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Vector; - -public class ASequenceFetcher -{ - - /** - * set of databases we can retrieve entries from - */ - protected Hashtable FETCHABLEDBS; - - public ASequenceFetcher() - { - super(); - } - - /** - * get list of supported Databases - * - * @return database source string for each database - only the latest version - * of a source db is bound to each source. - */ - public String[] getSupportedDb() - { - if (FETCHABLEDBS == null) - return null; - String[] sf = new String[FETCHABLEDBS.size()]; - Enumeration e = FETCHABLEDBS.keys(); - int i = 0; - while (e.hasMoreElements()) - { - sf[i++] = (String) e.nextElement(); - } - ; - return sf; - } - - public boolean isFetchable(String source) - { - Enumeration e = FETCHABLEDBS.keys(); - while (e.hasMoreElements()) - { - String db = (String) e.nextElement(); - if (source.compareToIgnoreCase(db) == 0) - return true; - } - jalview.bin.Cache.log.warn("isFetchable doesn't know about '" + source - + "'"); - return false; - } - - public SequenceI[] getSequences(jalview.datamodel.DBRefEntry[] refs) - { - SequenceI[] ret = null; - Vector rseqs = new Vector(); - Hashtable queries = new Hashtable(); - for (int r = 0; r < refs.length; r++) - { - if (!queries.containsKey(refs[r].getSource())) - { - queries.put(refs[r].getSource(), new Vector()); - } - Vector qset = (Vector) queries.get(refs[r].getSource()); - if (!qset.contains(refs[r].getAccessionId())) - { - qset.addElement(refs[r].getAccessionId()); - } - } - Enumeration e = queries.keys(); - while (e.hasMoreElements()) - { - Vector query = null; - String db = null; - try - { - db = (String) e.nextElement(); - query = (Vector) queries.get(db); - if (!isFetchable(db)) - throw new Exception( - "Don't know how to fetch from this database :" + db); - DbSourceProxy fetcher = getSourceProxy(db); - boolean doMultiple = fetcher.getAccessionSeparator() != null; // No - // separator - // - no - // Multiple - // Queries - Enumeration qs = query.elements(); - while (qs.hasMoreElements()) - { - StringBuffer qsb = new StringBuffer(); - do - { - qsb.append((String) qs.nextElement()); - if (qs.hasMoreElements() && doMultiple) // and not reached limit for - // multiple queries at one - // time for this source - { - qsb.append(fetcher.getAccessionSeparator()); - } - } while (doMultiple && qs.hasMoreElements()); - - AlignmentI seqset = null; - try - { - // create a fetcher and go to it - seqset = fetcher.getSequenceRecords(qsb.toString()); - } catch (Exception ex) - { - System.err.println("Failed to retrieve the following from " - + db); - System.err.println(qsb); - ex.printStackTrace(System.err); - } - // TODO: Merge alignment together - perhaps - if (seqset != null) - { - SequenceI seqs[] = seqset.getSequencesArray(); - if (seqs != null) - { - for (int is = 0; is < seqs.length; is++) - { - rseqs.addElement(seqs[is]); - seqs[is] = null; - } - } - else - { - if (fetcher.getRawRecords() != null) - { - System.out.println("# Retrieved from " + db + ":" - + qs.toString()); - StringBuffer rrb = fetcher.getRawRecords(); - /* - * for (int rr = 0; rr 10) - { - System.err.println(); - n = 0; - } - } - System.err.println(); - ex.printStackTrace(); - } - } - if (rseqs.size() > 0) - { - ret = new SequenceI[rseqs.size()]; - Enumeration sqs = rseqs.elements(); - int si = 0; - while (sqs.hasMoreElements()) - { - SequenceI s = (SequenceI) sqs.nextElement(); - ret[si++] = s; - s.updatePDBIds(); - } - } - return ret; - } - - /** - * Retrieve an instance of the proxy for the given source - * - * @param db - * database source string TODO: add version string/wildcard for - * retrieval of specific DB source/version combinations. - * @return an instance of DbSourceProxy for that db. - */ - public DbSourceProxy getSourceProxy(String db) - { - DbSourceProxy dbs = (DbSourceProxy) FETCHABLEDBS.get(db); - return dbs; - } - - /** - * constructs and instance of the proxy and registers it as a valid - * dbrefsource - * - * @param dbSourceProxy - * reference for class implementing - * jalview.ws.seqfetcher.DbSourceProxy - * @throws java.lang.IllegalArgumentException - * if class does not implement - * jalview.ws.seqfetcher.DbSourceProxy - */ - protected void addDBRefSourceImpl(Class dbSourceProxy) - throws java.lang.IllegalArgumentException - { - DbSourceProxy proxy = null; - try - { - Object proxyObj = dbSourceProxy.getConstructor(null) - .newInstance(null); - if (!DbSourceProxy.class.isInstance(proxyObj)) - { - throw new IllegalArgumentException( - dbSourceProxy.toString() - + " does not implement the jalview.ws.seqfetcher.DbSourceProxy"); - } - proxy = (DbSourceProxy) proxyObj; - } catch (IllegalArgumentException e) - { - throw e; - } catch (Exception e) - { - // Serious problems if this happens. - throw new Error("DBRefSource Implementation Exception", e); - } - addDbRefSourceImpl(proxy); - } - - /** - * add the properly initialised DbSourceProxy object 'proxy' to the list of - * sequence fetchers - * - * @param proxy - */ - protected void addDbRefSourceImpl(DbSourceProxy proxy) - { - if (proxy != null) - { - if (FETCHABLEDBS == null) - { - FETCHABLEDBS = new Hashtable(); - } - FETCHABLEDBS.put(proxy.getDbSource(), proxy); - } - } - - /** - * test if the database handler for dbName contains the given dbProperty - * - * @param dbName - * @param dbProperty - * @return true if proxy has the given property - */ - public boolean hasDbSourceProperty(String dbName, String dbProperty) - { - // TODO: decide if invalidDbName exception is thrown here. - DbSourceProxy proxy = getSourceProxy(dbName); - if (proxy != null) - { - if (proxy.getDbSourceProperties() != null) - { - return proxy.getDbSourceProperties().containsKey(dbProperty); - } - } - return false; - } - -} +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.ws.seqfetcher; + +import jalview.api.FeatureSettingsModelI; +import jalview.bin.Cache; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.SequenceI; +import jalview.util.DBRefUtils; +import jalview.util.MessageManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.Vector; + +public class ASequenceFetcher +{ + + /* + * set of databases we can retrieve entries from + */ + protected Hashtable> fetchableDbs; + + /* + * comparator to sort by tier (0/1/2) and name + */ + private Comparator proxyComparator; + + /** + * Constructor + */ + protected ASequenceFetcher() + { + super(); + + /* + * comparator to sort proxies by tier and name + */ + proxyComparator = new Comparator() + { + @Override + public int compare(DbSourceProxy o1, DbSourceProxy o2) + { + /* + * Tier 0 precedes 1 precedes 2 + */ + int compared = Integer.compare(o1.getTier(), o2.getTier()); + if (compared == 0) + { + // defend against NullPointer - should never happen + String o1Name = o1.getDbName(); + String o2Name = o2.getDbName(); + if (o1Name != null && o2Name != null) + { + compared = o1Name.compareToIgnoreCase(o2Name); + } + } + return compared; + } + }; + } + + /** + * get array of supported Databases + * + * @return database source string for each database - only the latest version + * of a source db is bound to each source. + */ + public String[] getSupportedDb() + { + if (fetchableDbs == null) + { + return null; + } + String[] sf = fetchableDbs.keySet() + .toArray(new String[fetchableDbs.size()]); + return sf; + } + + public boolean isFetchable(String source) + { + for (String db : fetchableDbs.keySet()) + { + if (source.equalsIgnoreCase(db)) + { + return true; + } + } + Cache.warn("isFetchable doesn't know about '" + source + "'"); + return false; + } + + /** + * Fetch sequences for the given cross-references + * + * @param refs + * @param dna + * if true, only fetch from nucleotide data sources, else peptide + * @return + */ + public SequenceI[] getSequences(List refs, boolean dna) + { + Vector rseqs = new Vector<>(); + Hashtable> queries = new Hashtable<>(); + for (DBRefEntry ref : refs) + { + String canonical = DBRefUtils.getCanonicalName(ref.getSource()); + if (!queries.containsKey(canonical)) + { + queries.put(canonical, new ArrayList()); + } + List qset = queries.get(canonical); + if (!qset.contains(ref.getAccessionId())) + { + qset.add(ref.getAccessionId()); + } + } + Enumeration e = queries.keys(); + while (e.hasMoreElements()) + { + List query = null; + String db = null; + db = e.nextElement(); + query = queries.get(db); + if (!isFetchable(db)) + { + reportStdError(db, query, new Exception( + "Don't know how to fetch from this database :" + db)); + continue; + } + + Stack queriesLeft = new Stack<>(); + queriesLeft.addAll(query); + + List proxies = getSourceProxy(db); + for (DbSourceProxy fetcher : proxies) + { + List queriesMade = new ArrayList<>(); + HashSet queriesFound = new HashSet<>(); + try + { + if (fetcher.isDnaCoding() != dna) + { + continue; // wrong sort of data + } + boolean doMultiple = fetcher.getMaximumQueryCount() > 1; + while (!queriesLeft.isEmpty()) + { + StringBuffer qsb = new StringBuffer(); + do + { + if (qsb.length() > 0) + { + qsb.append(fetcher.getAccessionSeparator()); + } + String q = queriesLeft.pop(); + queriesMade.add(q); + qsb.append(q); + } while (doMultiple && !queriesLeft.isEmpty()); + + AlignmentI seqset = null; + try + { + // create a fetcher and go to it + seqset = fetcher.getSequenceRecords(qsb.toString()); + } catch (Exception ex) + { + System.err.println( + "Failed to retrieve the following from " + db); + System.err.println(qsb); + ex.printStackTrace(System.err); + } + // TODO: Merge alignment together - perhaps + if (seqset != null) + { + SequenceI seqs[] = seqset.getSequencesArray(); + if (seqs != null) + { + for (int is = 0; is < seqs.length; is++) + { + rseqs.addElement(seqs[is]); + // BH 2015.01.25 check about version/accessid being null here + List frefs = DBRefUtils.searchRefs( + seqs[is].getDBRefs(), + new DBRefEntry(db, null, null), DBRefUtils.SEARCH_MODE_FULL); + for (DBRefEntry dbr : frefs) + { + queriesFound.add(dbr.getAccessionId()); + queriesMade.remove(dbr.getAccessionId()); + } + seqs[is] = null; + } + } + else + { + if (fetcher.getRawRecords() != null) + { + System.out.println( + "# Retrieved from " + db + ":" + qsb.toString()); + StringBuffer rrb = fetcher.getRawRecords(); + /* + * for (int rr = 0; rr 0) + { + System.out.println("# Adding " + queriesMade.size() + + " ids back to queries list for searching again (" + db + + ")"); + queriesLeft.addAll(queriesMade); + } + } + } + + SequenceI[] result = null; + if (rseqs.size() > 0) + { + result = new SequenceI[rseqs.size()]; + int si = 0; + for (SequenceI s : rseqs) + { + result[si++] = s; + s.updatePDBIds(); + } + } + return result; + } + + public void reportStdError(String db, List queriesMade, + Exception ex) + { + + System.err.println( + "Failed to retrieve the following references from " + db); + int n = 0; + for (String qv : queriesMade) + { + System.err.print(" " + qv + ";"); + if (n++ > 10) + { + System.err.println(); + n = 0; + } + } + System.err.println(); + ex.printStackTrace(); + } + + /** + * Returns a list of proxies for the given source + * + * @param db + * database source string TODO: add version string/wildcard for + * retrieval of specific DB source/version combinations. + * @return a list of DbSourceProxy for the db + */ + public List getSourceProxy(String db) + { + db = DBRefUtils.getCanonicalName(db); + Map dblist = fetchableDbs.get(db); + if (dblist == null) + { + return new ArrayList<>(); + } + + /* + * sort so that primary sources precede secondary + */ + List dbs = new ArrayList<>(dblist.values()); + Collections.sort(dbs, proxyComparator); + return dbs; + } + + /** + * constructs an instance of the proxy and registers it as a valid dbrefsource + * + * @param dbSourceProxy + * reference for class implementing + * jalview.ws.seqfetcher.DbSourceProxy + */ + protected void addDBRefSourceImpl( + Class dbSourceProxy) + throws IllegalArgumentException + { + DbSourceProxy proxy = null; + try + { + DbSourceProxy proxyObj = dbSourceProxy.getConstructor().newInstance(); + proxy = proxyObj; + } catch (IllegalArgumentException e) + { + throw e; + } catch (Exception e) + { + // Serious problems if this happens. + throw new Error(MessageManager + .getString("error.dbrefsource_implementation_exception"), e); + } + addDbRefSourceImpl(proxy); + } + + /** + * add the properly initialised DbSourceProxy object 'proxy' to the list of + * sequence fetchers + * + * @param proxy + */ + protected void addDbRefSourceImpl(DbSourceProxy proxy) + { + if (proxy != null) + { + if (fetchableDbs == null) + { + fetchableDbs = new Hashtable<>(); + } + Map slist = fetchableDbs + .get(proxy.getDbSource()); + if (slist == null) + { + fetchableDbs.put(proxy.getDbSource(), + slist = new Hashtable<>()); + } + slist.put(proxy.getDbName(), proxy); + } + } + + /** + * select sources which are implemented by instances of the given class + * + * @param class + * that implements DbSourceProxy + * @return null or vector of source names for fetchers + */ + public String[] getDbInstances(Class class1) + { + if (!DbSourceProxy.class.isAssignableFrom(class1)) + { + throw new Error(MessageManager.formatMessage( + "error.implementation_error_dbinstance_must_implement_interface", + new String[] + { class1.toString() })); + } + if (fetchableDbs == null) + { + return null; + } + String[] sources = null; + Vector src = new Vector<>(); + Enumeration dbs = fetchableDbs.keys(); + while (dbs.hasMoreElements()) + { + String dbn = dbs.nextElement(); + for (DbSourceProxy dbp : fetchableDbs.get(dbn).values()) + { + if (class1.isAssignableFrom(dbp.getClass())) + { + src.addElement(dbn); + } + } + } + if (src.size() > 0) + { + src.copyInto(sources = new String[src.size()]); + } + return sources; + } + + public DbSourceProxy[] getDbSourceProxyInstances(Class class1) + { + List prlist = new ArrayList<>(); + for (String fetchable : getSupportedDb()) + { + for (DbSourceProxy pr : getSourceProxy(fetchable)) + { + if (class1.isInstance(pr)) + { + prlist.add(pr); + } + } + } + if (prlist.size() == 0) + { + return null; + } + return prlist.toArray(new DbSourceProxy[0]); + } + + /** + * Returns a preferred feature colouring scheme for the given source, or null + * if none is defined. + * + * @param source + * @return + */ + public FeatureSettingsModelI getFeatureColourScheme(String source) + { + /* + * return the first non-null colour scheme for any proxy for + * this database source + */ + for (DbSourceProxy proxy : getSourceProxy(source)) + { + FeatureSettingsModelI preferredColours = proxy + .getFeatureColourScheme(); + if (preferredColours != null) + { + return preferredColours; + } + } + return null; + } +}