fetch database references for all EBI db + selected das sequence sources or a specifi...
[jalview.git] / src / jalview / ws / DBRefFetcher.java
index ba6d57f..be0a8b0 100644 (file)
@@ -1,17 +1,17 @@
 /*\r
- * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
- *\r
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)\r
+ * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
+ * \r
  * This program 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 2\r
  * of the License, or (at your option) any later version.\r
- *\r
+ * \r
  * This program is distributed in the hope that it will be useful,\r
  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
  * GNU General Public License for more details.\r
- *\r
+ * \r
  * You should have received a copy of the GNU General Public License\r
  * along with this program; if not, write to the Free Software\r
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
@@ -21,6 +21,7 @@ package jalview.ws;
 import java.io.*;\r
 import java.util.*;\r
 \r
+import org.biojava.dasobert.dasregistry.DasSource;\r
 import org.exolab.castor.mapping.*;\r
 import org.exolab.castor.xml.*;\r
 import jalview.analysis.*;\r
@@ -31,7 +32,8 @@ import jalview.ws.dbsources.Uniprot;
 import jalview.ws.ebi.EBIFetchClient;\r
 \r
 /**\r
- * DOCUMENT ME!\r
+ * Implements a runnable for validating a sequence against external databases\r
+ * and then propagating references and features onto the sequence(s)\r
  * \r
  * @author $author$\r
  * @version $Revision$\r
@@ -40,7 +42,7 @@ public class DBRefFetcher implements Runnable
 {\r
   SequenceI[] dataset;\r
 \r
-  AlignFrame af;\r
+  IProgressIndicator af;\r
 \r
   CutAndPasteTransfer output = new CutAndPasteTransfer();\r
 \r
@@ -61,7 +63,8 @@ public class DBRefFetcher implements Runnable
   }\r
 \r
   /**\r
-   * Creates a new SequenceFeatureFetcher object.\r
+   * Creates a new SequenceFeatureFetcher object and fetches from the\r
+   * currently selected set of databases.\r
    * \r
    * @param seqs\r
    *                fetch references for these sequences\r
@@ -70,6 +73,20 @@ public class DBRefFetcher implements Runnable
    */\r
   public DBRefFetcher(SequenceI[] seqs, AlignFrame af)\r
   {\r
+    this(seqs, af, null);\r
+  }\r
+  /**\r
+   * Creates a new SequenceFeatureFetcher object and fetches from the\r
+   * currently selected set of databases.\r
+   * \r
+   * @param seqs\r
+   *                fetch references for these sequences\r
+   * @param af\r
+   *                the parent alignframe for progress bar monitoring.\r
+   * @param sources array of database source strings to query references from\r
+   */\r
+  public DBRefFetcher(SequenceI[] seqs, AlignFrame af, String[] sources)\r
+  {\r
     this.af = af;\r
     SequenceI[] ds = new SequenceI[seqs.length];\r
     for (int i = 0; i < seqs.length; i++)\r
@@ -80,18 +97,73 @@ public class DBRefFetcher implements Runnable
         ds[i] = seqs[i];\r
     }\r
     this.dataset = ds;\r
-    sfetcher = new SequenceFetcher();\r
-    // select appropriate databases based on alignFrame context.\r
-    if (af.getViewport().getAlignment().isNucleotide())\r
+    // TODO Jalview 2.5 lots of this code should be in the gui package!\r
+    sfetcher = jalview.gui.SequenceFetcher.getSequenceFetcherSingleton(af);\r
+    if (sources==null)\r
     {\r
-      dbSources = DBRefSource.DNACODINGDBS;\r
+      // af.featureSettings_actionPerformed(null);\r
+      String[] defdb=null,otherdb = sfetcher.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);\r
+      Vector selsources = new Vector(), dasselsrc= (af.featureSettings!=null) ? af.featureSettings.getSelectedSources()\r
+              : new jalview.gui.DasSourceBrowser().getSelectedSources();\r
+      Enumeration en = dasselsrc.elements();\r
+      while (en.hasMoreElements())\r
+      {\r
+        DasSource src = (DasSource) en.nextElement();\r
+        selsources.addElement(src.getNickname());\r
+      }\r
+      int osel = 0;\r
+      for (int o=0;otherdb!=null && o<otherdb.length;o++)\r
+      {\r
+        if (!selsources.contains(otherdb[o]))\r
+        {\r
+          otherdb[o] = null;\r
+        } else {\r
+          osel++;\r
+        }\r
+      }\r
+      // select appropriate databases based on alignFrame context.\r
+      if (af.getViewport().getAlignment().isNucleotide())\r
+      {\r
+        defdb = DBRefSource.DNACODINGDBS;\r
+      }\r
+      else\r
+      {\r
+        defdb = DBRefSource.PROTEINDBS;\r
+      }\r
+      // append the selected sequence sources to the default dbs \r
+      dbSources = new String[defdb.length+osel];\r
+      System.arraycopy(defdb, 0, dbSources, 0, defdb.length);\r
+      for (int o=0,op=defdb.length; otherdb!=null && o<otherdb.length; o++)\r
+      {\r
+        if (otherdb[o]!=null)\r
+        {\r
+          dbSources[op++] = otherdb[o];\r
+        }\r
+      }\r
+    } else {\r
+      // we assume the caller knows what they're doing and ensured that all the db source names are valid\r
+      dbSources = sources;\r
     }\r
-    else\r
+  }\r
+  /**\r
+   * retrieve all the das sequence sources and add them to the list of db sources to retrieve from \r
+   */\r
+  public void appendAllDasSources()\r
+  {\r
+    if (dbSources == null)\r
     {\r
-      dbSources = DBRefSource.PROTEINDBS;\r
+      dbSources = new String[] {};\r
+    }\r
+    // append additional sources\r
+    String[] otherdb = sfetcher.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);\r
+    if (otherdb!=null && otherdb.length>0)\r
+    {\r
+      String[] newsrc = new String[dbSources.length+otherdb.length];\r
+      System.arraycopy(dbSources, 0, newsrc,0,dbSources.length);\r
+      System.arraycopy(otherdb, 0, newsrc,dbSources.length, otherdb.length);\r
+      dbSources = newsrc;\r
     }\r
   }\r
-\r
   /**\r
    * start the fetcher thread\r
    * \r
@@ -192,6 +264,10 @@ public class DBRefFetcher implements Runnable
         maxqlen = ((Integer) dbsource.getDbSourceProperties().get(\r
                 DBRefSource.MULTIACC)).intValue();\r
       }\r
+      else\r
+      {\r
+        maxqlen = 1;\r
+      }\r
       // iterate through db for each remaining un-verified sequence\r
       SequenceI[] currSeqs = new SequenceI[sdataset.size()];\r
       sdataset.copyInto(currSeqs);// seqs that are to be validated against\r
@@ -207,31 +283,38 @@ public class DBRefFetcher implements Runnable
         {\r
           // Still queries to make for current seqIndex\r
           StringBuffer queryString = new StringBuffer("");\r
-          int nqSize = (maxqlen > queries.size()) ? queries.size()\r
+          int numq=0,nqSize = (maxqlen > queries.size()) ? queries.size()\r
                   : maxqlen;\r
-          for (int nq = 0, numq = 0; nq < nqSize; nq++)\r
+          \r
+          while (queries.size()>0 && numq < nqSize)\r
           {\r
-            String query = (String) queries.elementAt(nq);\r
+            String query = (String) queries.elementAt(0);\r
             if (dbsource.isValidReference(query))\r
             {\r
-              queryString.append((nq == 0) ? "" : dbsource\r
+              queryString.append((numq == 0) ? "" : dbsource\r
                       .getAccessionSeparator());\r
               queryString.append(query);\r
               numq++;\r
             }\r
-          }\r
-          for (int nq = 0; nq < nqSize; nq++)\r
-          {\r
+            // remove the extracted query string\r
             queries.removeElementAt(0);\r
           }\r
           // make the queries and process the response\r
           AlignmentI retrieved = null;\r
           try\r
           {\r
+            if (jalview.bin.Cache.log.isDebugEnabled())\r
+            {\r
+              jalview.bin.Cache.log.debug("Querying "+dbsource.getDbName()+" with : '"+queryString.toString()+"'");\r
+            }\r
             retrieved = dbsource.getSequenceRecords(queryString.toString());\r
           } catch (Exception ex)\r
           {\r
             ex.printStackTrace();\r
+          } catch (OutOfMemoryError err)\r
+          {\r
+            new OOMWarning("retrieving database references ("\r
+                    + queryString.toString() + ")", err);\r
           }\r
           if (retrieved != null)\r
           {\r
@@ -249,7 +332,7 @@ public class DBRefFetcher implements Runnable
                     { dbSources[db] }); // jalview.datamodel.DBRefSource.UNIPROT\r
             // });\r
             // check for existing dbrefs to use\r
-            if (uprefs != null)\r
+            if (uprefs != null && uprefs.length>0)\r
             {\r
               for (int j = 0; j < uprefs.length; j++)\r
               {\r
@@ -346,14 +429,15 @@ public class DBRefFetcher implements Runnable
           }\r
         }\r
       }\r
-      if (sequenceMatches.size()==0)\r
+      if (sequenceMatches.size() == 0)\r
       {\r
-        // failed to match directly on accessionId==query so just compare all sequences to entry\r
+        // failed to match directly on accessionId==query so just compare all\r
+        // sequences to entry\r
         Enumeration e = seqRefs.keys();\r
         while (e.hasMoreElements())\r
         {\r
           Vector sqs = (Vector) seqRefs.get(e.nextElement());\r
-          if (sqs!=null && sqs.size()>0)\r
+          if (sqs != null && sqs.size() > 0)\r
           {\r
             Enumeration sqe = sqs.elements();\r
             while (sqe.hasMoreElements())\r
@@ -383,9 +467,12 @@ public class DBRefFetcher implements Runnable
       for (int m = 0; m < sequenceMatches.size(); m++)\r
       {\r
         sequence = (SequenceI) sequenceMatches.elementAt(m);\r
-        // only update start and end positions and shift features if there are no existing references\r
-        // TODO: test for legacy where uniprot or EMBL refs exist but no mappings are made (but content matches retrieved set)\r
-        boolean updateRefFrame = sequence.getDBRef()==null || sequence.getDBRef().length==0;\r
+        // only update start and end positions and shift features if there are\r
+        // no existing references\r
+        // TODO: test for legacy where uniprot or EMBL refs exist but no\r
+        // mappings are made (but content matches retrieved set)\r
+        boolean updateRefFrame = sequence.getDBRef() == null\r
+                || sequence.getDBRef().length == 0;\r
         // verify sequence against the entry sequence\r
 \r
         String nonGapped = AlignSeq.extractGaps("-. ",\r
@@ -405,20 +492,23 @@ public class DBRefFetcher implements Runnable
                     + " SEQUENCE NOT %100 MATCH \n");\r
             continue;\r
           }\r
-          \r
+\r
           sbuffer.append(sequence.getName() + " HAS " + absStart\r
-                + " PREFIXED RESIDUES COMPARED TO " + dbSource+"\n");\r
+                  + " PREFIXED RESIDUES COMPARED TO " + dbSource + "\n");\r
           //\r
-          //      + " - ANY SEQUENCE FEATURES"\r
-          //        + " HAVE BEEN ADJUSTED ACCORDINGLY \n");\r
+          // + " - ANY SEQUENCE FEATURES"\r
+          // + " HAVE BEEN ADJUSTED ACCORDINGLY \n");\r
           // absStart = 0;\r
           // create valid mapping between matching region of local sequence and\r
           // the mapped sequence\r
           mp = new Mapping(null, new int[]\r
-          { sequence.getStart()+absStart, sequence.getStart()+absStart+entrySeq.length()-1 }, new int[]\r
-          { entry.getStart(),\r
-              entry.getStart() + entrySeq.length() - 1 }, 1, 1);\r
-          updateRefFrame=false; // mapping is based on current start/end so don't modify start and end\r
+          { sequence.getStart() + absStart,\r
+              sequence.getStart() + absStart + entrySeq.length() - 1 },\r
+                  new int[]\r
+                  { entry.getStart(),\r
+                      entry.getStart() + entrySeq.length() - 1 }, 1, 1);\r
+          updateRefFrame = false; // mapping is based on current start/end so\r
+          // don't modify start and end\r
         }\r
         else\r
         {\r
@@ -438,7 +528,8 @@ public class DBRefFetcher implements Runnable
             SequenceFeature[] sf = sequence.getSequenceFeatures();\r
             int start = sequence.getStart();\r
             int end = sequence.getEnd();\r
-            int startShift = 1-absStart-start; // how much the features are to be shifted by\r
+            int startShift = 1 - absStart - start; // how much the features are\r
+            // to be shifted by\r
             for (int sfi = 0; sfi < sf.length; sfi++)\r
             {\r
               if (sf[sfi].getBegin() >= start && sf[sfi].getEnd() <= end)\r