JAL-2253 safer simpler resolution of identifiers using lookup endpoint;
[jalview.git] / src / jalview / ext / ensembl / EnsemblGene.java
index fa1e474..902f745 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.api.FeatureColourI;
@@ -8,10 +28,9 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyI;
-import jalview.schemes.FeatureColourAdapter;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.FeatureSettingsAdapter;
 import jalview.util.MapList;
-import jalview.util.StringUtils;
 
 import java.awt.Color;
 import java.io.UnsupportedEncodingException;
@@ -29,9 +48,6 @@ import com.stevesoft.pat.Regex;
  */
 public class EnsemblGene extends EnsemblSeqProxy
 {
-  private static final List<String> CROSS_REFERENCES = Arrays
-          .asList(new String[] { "CCDS" });
-
   private static final String GENE_PREFIX = "gene:";
 
   /*
@@ -104,82 +120,87 @@ public class EnsemblGene extends EnsemblSeqProxy
    * </ul>
    * 
    * @param query
-   *          one or more identifiers separated by a space
-   * @return an alignment containing one or more genes, and possibly
-   *         transcripts, or null
+   *          a single gene or transcript identifier or gene name
+   * @return an alignment containing a gene, and possibly transcripts, or null
    */
   @Override
   public AlignmentI getSequenceRecords(String query) throws Exception
   {
-    // todo: tidy up handling of one or multiple accession ids
-    String[] queries = query.split(getAccessionSeparator());
-
     /*
-     * if given a transcript id, look up its gene parent
+     * convert to a non-duplicated list of gene identifiers
      */
-    if (isTranscriptIdentifier(query))
+    List<String> geneIds = getGeneIds(query);
+
+    AlignmentI al = null;
+    for (String geneId : geneIds)
     {
-      // we are assuming all transcripts have the same gene parent here
-      query = new EnsemblLookup(getDomain()).getParent(queries[0]);
-      if (query == null)
+      /*
+       * fetch the gene sequence(s) with features and xrefs
+       */
+      AlignmentI geneAlignment = super.getSequenceRecords(geneId);
+      if (geneAlignment == null)
       {
-        return null;
+        continue;
       }
-    }
-
-    /*
-     * if given a gene or other external name, lookup and fetch 
-     * the corresponding gene for all model organisms 
-     */
-    if (!isGeneIdentifier(query))
-    {
-      List<String> geneIds = new EnsemblSymbol(getDomain()).getIds(query);
-      if (geneIds.isEmpty())
+      if (geneAlignment.getHeight() == 1)
       {
-        return null;
+        getTranscripts(geneAlignment, geneId);
+      }
+      if (al == null)
+      {
+        al = geneAlignment;
+      }
+      else
+      {
+        al.append(geneAlignment);
       }
-      String theIds = StringUtils.listToDelimitedString(geneIds,
-              getAccessionSeparator());
-      return getSequenceRecords(theIds);
-    }
-
-    /*
-     * fetch the gene sequence(s) with features and xrefs
-     */
-    AlignmentI al = super.getSequenceRecords(query);
-
-    /*
-     * if we retrieved a single gene, get its transcripts as well
-     */
-    if (al.getHeight() == 1)
-    {
-      getTranscripts(al, query);
     }
-
     return al;
   }
 
   /**
-   * Attempts to get Ensembl stable identifiers for model organisms for a gene
-   * name by calling the xrefs symbol REST service to resolve the gene name.
+   * Converts a query, which may contain one or more gene, transcript, or
+   * external (to Ensembl) identifiers, into a non-redundant list of gene
+   * identifiers.
    * 
-   * @param query
+   * @param accessions
    * @return
    */
-  protected String getGeneIdentifiersForName(String query)
+  List<String> getGeneIds(String accessions)
   {
-    List<String> ids = new EnsemblSymbol(getDomain()).getIds(query);
-    if (ids != null)
+    List<String> geneIds = new ArrayList<String>();
+
+    for (String acc : accessions.split(getAccessionSeparator()))
     {
-      for (String id : ids)
+      /*
+       * First try lookup as an Ensembl (gene or transcript) identifier
+       */
+      String geneId = new EnsemblLookup(getDomain()).getGeneId(acc);
+      if (geneId != null)
       {
-        if (isGeneIdentifier(id))
+        if (!geneIds.contains(geneId))
         {
-          return id;
+          geneIds.add(geneId);
+        }
+      }
+      else
+      {
+        /*
+         * if given a gene or other external name, lookup and fetch 
+         * the corresponding gene for all model organisms 
+         */
+        List<String> ids = new EnsemblSymbol(getDomain(), getDbSource(),
+                getDbVersion()).getGeneIds(acc);
+        for (String id : ids)
+        {
+          if (!geneIds.contains(id))
+          {
+            geneIds.add(id);
+          }
         }
       }
     }
-    return null;
+    return geneIds;
   }
 
   /**
@@ -229,8 +250,7 @@ public class EnsemblGene extends EnsemblSeqProxy
         }
       }
       gene.setSequenceFeatures(filtered
-              .toArray(new SequenceFeature[filtered
-              .size()]));
+              .toArray(new SequenceFeature[filtered.size()]));
     }
   }
 
@@ -465,15 +485,6 @@ public class EnsemblGene extends EnsemblSeqProxy
     return false;
   }
 
-  @Override
-  protected List<String> getCrossReferenceDatabases()
-  {
-    // found these for ENSG00000157764 on 30/01/2016:
-    // return new String[] {"Vega_gene", "OTTG", "ENS_LRG_gene", "ArrayExpress",
-    // "EntrezGene", "HGNC", "MIM_GENE", "MIM_MORBID", "WikiGene"};
-    return CROSS_REFERENCES;
-  }
-
   /**
    * Override to do nothing as Ensembl doesn't return a protein sequence for a
    * gene identifier
@@ -505,6 +516,7 @@ public class EnsemblGene extends EnsemblSeqProxy
     return new FeatureSettingsAdapter()
     {
       SequenceOntologyI so = SequenceOntologyFactory.getInstance();
+
       @Override
       public boolean isFeatureDisplayed(String type)
       {
@@ -517,7 +529,7 @@ public class EnsemblGene extends EnsemblSeqProxy
       {
         if (so.isA(type, SequenceOntologyI.EXON))
         {
-          return new FeatureColourAdapter()
+          return new FeatureColour()
           {
             @Override
             public boolean isColourByLabel()
@@ -528,7 +540,7 @@ public class EnsemblGene extends EnsemblSeqProxy
         }
         if (so.isA(type, SequenceOntologyI.SEQUENCE_VARIANT))
         {
-          return new FeatureColourAdapter()
+          return new FeatureColour()
           {
 
             @Override