-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)\r
- * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle\r
- * \r
- * This file is part of Jalview.\r
- * \r
- * Jalview is free software: you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License \r
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
- * \r
- * Jalview is distributed in the hope that it will be useful, but \r
- * WITHOUT ANY WARRANTY; without even the implied warranty \r
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
- * PURPOSE. See the GNU General Public License for more details.\r
- * \r
- * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-package jalview.ws.seqfetcher;\r
-\r
-import jalview.datamodel.AlignmentI;\r
-import jalview.datamodel.SequenceI;\r
-\r
-import java.util.Enumeration;\r
-import java.util.Hashtable;\r
-import java.util.Vector;\r
-\r
-public class ASequenceFetcher\r
-{\r
-\r
- /**\r
- * set of databases we can retrieve entries from\r
- */\r
- protected Hashtable FETCHABLEDBS;\r
-\r
- public ASequenceFetcher()\r
- {\r
- super();\r
- }\r
-\r
- /**\r
- * get list of supported Databases\r
- * \r
- * @return database source string for each database - only the latest version\r
- * of a source db is bound to each source.\r
- */\r
- public String[] getSupportedDb()\r
- {\r
- if (FETCHABLEDBS == null)\r
- return null;\r
- String[] sf = new String[FETCHABLEDBS.size()];\r
- Enumeration e = FETCHABLEDBS.keys();\r
- int i = 0;\r
- while (e.hasMoreElements())\r
- {\r
- sf[i++] = (String) e.nextElement();\r
- }\r
- ;\r
- return sf;\r
- }\r
-\r
- public boolean isFetchable(String source)\r
- {\r
- Enumeration e = FETCHABLEDBS.keys();\r
- while (e.hasMoreElements())\r
- {\r
- String db = (String) e.nextElement();\r
- if (source.compareToIgnoreCase(db) == 0)\r
- return true;\r
- }\r
- jalview.bin.Cache.log.warn("isFetchable doesn't know about '" + source\r
- + "'");\r
- return false;\r
- }\r
-\r
- public SequenceI[] getSequences(jalview.datamodel.DBRefEntry[] refs)\r
- {\r
- SequenceI[] ret = null;\r
- Vector rseqs = new Vector();\r
- Hashtable queries = new Hashtable();\r
- for (int r = 0; r < refs.length; r++)\r
- {\r
- if (!queries.containsKey(refs[r].getSource()))\r
- {\r
- queries.put(refs[r].getSource(), new Vector());\r
- }\r
- Vector qset = (Vector) queries.get(refs[r].getSource());\r
- if (!qset.contains(refs[r].getAccessionId()))\r
- {\r
- qset.addElement(refs[r].getAccessionId());\r
- }\r
- }\r
- Enumeration e = queries.keys();\r
- while (e.hasMoreElements())\r
- {\r
- Vector query = null;\r
- String db = null;\r
- try\r
- {\r
- db = (String) e.nextElement();\r
- query = (Vector) queries.get(db);\r
- if (!isFetchable(db))\r
- throw new Exception(\r
- "Don't know how to fetch from this database :" + db);\r
- DbSourceProxy fetcher = getSourceProxy(db);\r
- boolean doMultiple = fetcher.getAccessionSeparator() != null; // No\r
- // separator\r
- // - no\r
- // Multiple\r
- // Queries\r
- Enumeration qs = query.elements();\r
- while (qs.hasMoreElements())\r
- {\r
- StringBuffer qsb = new StringBuffer();\r
- do\r
- {\r
- qsb.append((String) qs.nextElement());\r
- if (qs.hasMoreElements() && doMultiple) // and not reached limit for\r
- // multiple queries at one\r
- // time for this source\r
- {\r
- qsb.append(fetcher.getAccessionSeparator());\r
- }\r
- } while (doMultiple && qs.hasMoreElements());\r
-\r
- AlignmentI seqset = null;\r
- try\r
- {\r
- // create a fetcher and go to it\r
- seqset = fetcher.getSequenceRecords(qsb.toString());\r
- } catch (Exception ex)\r
- {\r
- System.err.println("Failed to retrieve the following from "\r
- + db);\r
- System.err.println(qsb);\r
- ex.printStackTrace(System.err);\r
- }\r
- // TODO: Merge alignment together - perhaps\r
- if (seqset != null)\r
- {\r
- SequenceI seqs[] = seqset.getSequencesArray();\r
- if (seqs != null)\r
- {\r
- for (int is = 0; is < seqs.length; is++)\r
- {\r
- rseqs.addElement(seqs[is]);\r
- seqs[is] = null;\r
- }\r
- }\r
- else\r
- {\r
- if (fetcher.getRawRecords() != null)\r
- {\r
- System.out.println("# Retrieved from " + db + ":"\r
- + qs.toString());\r
- StringBuffer rrb = fetcher.getRawRecords();\r
- /*\r
- * for (int rr = 0; rr<rrb.length; rr++) {\r
- */\r
- String hdr;\r
- // if (rr<qs.length)\r
- // {\r
- hdr = "# " + db + ":" + qsb.toString();\r
- /*\r
- * } else { hdr = "# part "+rr; }\r
- */\r
- System.out.println(hdr);\r
- if (rrb != null)\r
- System.out.println(rrb);\r
- System.out.println("# end of " + hdr);\r
- }\r
- }\r
- }\r
- }\r
- } catch (Exception ex)\r
- {\r
- System.err\r
- .println("Failed to retrieve the following references from "\r
- + db);\r
- Enumeration qv = query.elements();\r
- int n = 0;\r
- while (qv.hasMoreElements())\r
- {\r
- System.err.print(" " + qv.nextElement() + ";");\r
- if (n++ > 10)\r
- {\r
- System.err.println();\r
- n = 0;\r
- }\r
- }\r
- System.err.println();\r
- ex.printStackTrace();\r
- }\r
- }\r
- if (rseqs.size() > 0)\r
- {\r
- ret = new SequenceI[rseqs.size()];\r
- Enumeration sqs = rseqs.elements();\r
- int si = 0;\r
- while (sqs.hasMoreElements())\r
- {\r
- SequenceI s = (SequenceI) sqs.nextElement();\r
- ret[si++] = s;\r
- s.updatePDBIds();\r
- }\r
- }\r
- return ret;\r
- }\r
-\r
- /**\r
- * Retrieve an instance of the proxy for the given source\r
- * \r
- * @param db\r
- * database source string TODO: add version string/wildcard for\r
- * retrieval of specific DB source/version combinations.\r
- * @return an instance of DbSourceProxy for that db.\r
- */\r
- public DbSourceProxy getSourceProxy(String db)\r
- {\r
- DbSourceProxy dbs = (DbSourceProxy) FETCHABLEDBS.get(db);\r
- return dbs;\r
- }\r
-\r
- /**\r
- * constructs and instance of the proxy and registers it as a valid\r
- * dbrefsource\r
- * \r
- * @param dbSourceProxy\r
- * reference for class implementing\r
- * jalview.ws.seqfetcher.DbSourceProxy\r
- * @throws java.lang.IllegalArgumentException\r
- * if class does not implement jalview.ws.seqfetcher.DbSourceProxy\r
- */\r
- protected void addDBRefSourceImpl(Class dbSourceProxy)\r
- throws java.lang.IllegalArgumentException\r
- {\r
- DbSourceProxy proxy = null;\r
- try\r
- {\r
- Object proxyObj = dbSourceProxy.getConstructor(null)\r
- .newInstance(null);\r
- if (!DbSourceProxy.class.isInstance(proxyObj))\r
- {\r
- throw new IllegalArgumentException(\r
- dbSourceProxy.toString()\r
- + " does not implement the jalview.ws.seqfetcher.DbSourceProxy");\r
- }\r
- proxy = (DbSourceProxy) proxyObj;\r
- } catch (IllegalArgumentException e)\r
- {\r
- throw e;\r
- } catch (Exception e)\r
- {\r
- // Serious problems if this happens.\r
- throw new Error("DBRefSource Implementation Exception", e);\r
- }\r
- addDbRefSourceImpl(proxy);\r
- }\r
-\r
- /**\r
- * add the properly initialised DbSourceProxy object 'proxy' to the list of\r
- * sequence fetchers\r
- * \r
- * @param proxy\r
- */\r
- protected void addDbRefSourceImpl(DbSourceProxy proxy)\r
- {\r
- if (proxy != null)\r
- {\r
- if (FETCHABLEDBS == null)\r
- {\r
- FETCHABLEDBS = new Hashtable();\r
- }\r
- FETCHABLEDBS.put(proxy.getDbSource(), proxy);\r
- }\r
- }\r
-\r
- /**\r
- * test if the database handler for dbName contains the given dbProperty\r
- * \r
- * @param dbName\r
- * @param dbProperty\r
- * @return true if proxy has the given property\r
- */\r
- public boolean hasDbSourceProperty(String dbName, String dbProperty)\r
- {\r
- // TODO: decide if invalidDbName exception is thrown here.\r
- DbSourceProxy proxy = getSourceProxy(dbName);\r
- if (proxy != null)\r
- {\r
- if (proxy.getDbSourceProperties() != null)\r
- {\r
- return proxy.getDbSourceProperties().containsKey(dbProperty);\r
- }\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * select sources which are implemented by instances of the given class\r
- * \r
- * @param class that implements DbSourceProxy\r
- * @return null or vector of source names for fetchers\r
- */\r
- public String[] getDbInstances(Class class1)\r
- {\r
- if (!jalview.ws.seqfetcher.DbSourceProxy.class.isAssignableFrom(class1))\r
- {\r
- throw new Error(\r
- "Implmentation Error - getDbInstances must be given a class that implements jalview.ws.seqfetcher.DbSourceProxy (was given '"\r
- + class1 + "')");\r
- }\r
- if (FETCHABLEDBS == null)\r
- {\r
- return null;\r
- }\r
- String[] sources = null;\r
- Vector src = new Vector();\r
- Enumeration dbs = FETCHABLEDBS.keys();\r
- while (dbs.hasMoreElements())\r
- {\r
- String dbn = (String) dbs.nextElement();\r
- DbSourceProxy dbp = (DbSourceProxy) FETCHABLEDBS.get(dbn);\r
- if (class1.isAssignableFrom(dbp.getClass()))\r
- {\r
- src.addElement(dbn);\r
- }\r
- }\r
- if (src.size() > 0)\r
- {\r
- src.copyInto(sources = new String[src.size()]);\r
- }\r
- return sources;\r
- }\r
-}\r
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * 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<String, Map<String, DbSourceProxy>> fetchableDbs;
+
+ /*
+ * comparator to sort by tier (0/1/2) and name
+ */
+ private Comparator<DbSourceProxy> proxyComparator;
+
+ /**
+ * Constructor
+ */
+ protected ASequenceFetcher()
+ {
+ super();
+
+ /*
+ * comparator to sort proxies by tier and name
+ */
+ proxyComparator = new Comparator<DbSourceProxy>()
+ {
+ @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.log.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<DBRefEntry> refs, boolean dna)
+ {
+ Vector<SequenceI> rseqs = new Vector<>();
+ Hashtable<String, List<String>> queries = new Hashtable<>();
+ for (DBRefEntry ref : refs)
+ {
+ String canonical = DBRefUtils.getCanonicalName(ref.getSource());
+ if (!queries.containsKey(canonical))
+ {
+ queries.put(canonical, new ArrayList<String>());
+ }
+ List<String> qset = queries.get(canonical);
+ if (!qset.contains(ref.getAccessionId()))
+ {
+ qset.add(ref.getAccessionId());
+ }
+ }
+ Enumeration<String> e = queries.keys();
+ while (e.hasMoreElements())
+ {
+ List<String> 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<String> queriesLeft = new Stack<>();
+ queriesLeft.addAll(query);
+
+ List<DbSourceProxy> proxies = getSourceProxy(db);
+ for (DbSourceProxy fetcher : proxies)
+ {
+ List<String> queriesMade = new ArrayList<>();
+ HashSet<String> 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<DBRefEntry> 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<rrb.length; rr++) {
+ */
+ String hdr;
+ // if (rr<qs.length)
+ // {
+ hdr = "# " + db + ":" + qsb.toString();
+ /*
+ * } else { hdr = "# part "+rr; }
+ */
+ System.out.println(hdr);
+ if (rrb != null)
+ {
+ System.out.println(rrb);
+ }
+ System.out.println("# end of " + hdr);
+ }
+
+ }
+ }
+
+ }
+ } catch (Exception ex)
+ {
+ reportStdError(db, queriesMade, ex);
+ }
+ if (queriesMade.size() > 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<String> 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<DbSourceProxy> getSourceProxy(String db)
+ {
+ db = DBRefUtils.getCanonicalName(db);
+ Map<String, DbSourceProxy> dblist = fetchableDbs.get(db);
+ if (dblist == null)
+ {
+ return new ArrayList<>();
+ }
+
+ /*
+ * sort so that primary sources precede secondary
+ */
+ List<DbSourceProxy> 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<? extends DbSourceProxy> 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<String, DbSourceProxy> 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<String> src = new Vector<>();
+ Enumeration<String> 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<DbSourceProxy> 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;
+ }
+}