Merge branch 'develop' into features/JAL-1793VCF; lambda Function for
[jalview.git] / src / jalview / ext / ensembl / EnsemblLookup.java
index 0968663..f314b0a 100644 (file)
@@ -28,17 +28,16 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.Function;
 
 import org.json.simple.JSONObject;
 import org.json.simple.parser.JSONParser;
 import org.json.simple.parser.ParseException;
 
 /**
- * A client for the Ensembl lookup REST endpoint; used to find the Parent gene
- * identifier given a transcript identifier.
+ * A client for the Ensembl lookup REST endpoint
  * 
  * @author gmcarstairs
- *
  */
 public class EnsemblLookup extends EnsemblRestClient
 {
@@ -46,6 +45,12 @@ public class EnsemblLookup extends EnsemblRestClient
 
   private static final String PARENT = "Parent";
 
+  private static final String OBJECT_TYPE_TRANSLATION = "Translation";
+  private static final String OBJECT_TYPE_TRANSCRIPT = "Transcript";
+  private static final String ID = "id";
+  private static final String OBJECT_TYPE_GENE = "Gene";
+  private static final String OBJECT_TYPE = "object_type";
+
   /**
    * Default constructor (to use rest.ensembl.org)
    */
@@ -90,7 +95,7 @@ public class EnsemblLookup extends EnsemblRestClient
   protected URL getUrl(String identifier)
   {
     String url = getDomain() + "/lookup/id/" + identifier
-            + "?content-type=application/json";
+            + CONTENT_TYPE_JSON;
     try
     {
       return new URL(url);
@@ -125,9 +130,9 @@ public class EnsemblLookup extends EnsemblRestClient
    * @param identifier
    * @return
    */
-  public String getParent(String identifier)
+  public String getGeneId(String identifier)
   {
-    return getAttribute(identifier, PARENT);
+    return getResult(identifier, br -> parseGeneId(br));
   }
 
   /**
@@ -139,7 +144,7 @@ public class EnsemblLookup extends EnsemblRestClient
    */
   public String getSpecies(String identifier)
   {
-    return getAttribute(identifier, SPECIES);
+    return getResult(identifier, br -> getAttribute(br, SPECIES));
   }
 
   /**
@@ -147,7 +152,8 @@ public class EnsemblLookup extends EnsemblRestClient
    * @param attribute
    * @return
    */
-  protected String getAttribute(String identifier, String attribute)
+  protected String getResult(String identifier,
+          Function<BufferedReader, String> parser)
   {
     List<String> ids = Arrays.asList(new String[] { identifier });
 
@@ -159,7 +165,7 @@ public class EnsemblLookup extends EnsemblRestClient
       {
         br = getHttpResponse(url, ids);
       }
-      return (parseResponse(br, attribute));
+      return br == null ? null : parser.apply(br);
     } catch (IOException e)
     {
       // ignore
@@ -180,27 +186,75 @@ public class EnsemblLookup extends EnsemblRestClient
   }
 
   /**
-   * Parses the value of 'attribute' from the JSON response and returns the
-   * value, or null if not found
+   * Answers the value of 'attribute' from the JSON response, or null if not
+   * found
    * 
    * @param br
    * @param attribute
    * @return
-   * @throws IOException
    */
-  protected String parseResponse(BufferedReader br, String attribute) throws IOException
+  protected String getAttribute(BufferedReader br, String attribute)
+  {
+    String value = null;
+    JSONParser jp = new JSONParser();
+    try
+    {
+      JSONObject val = (JSONObject) jp.parse(br);
+      value = val.get(attribute).toString();
+    } catch (ParseException | NullPointerException | IOException e)
+    {
+      // ignore
+    }
+    return value;
+  }
+
+  /**
+   * Parses the JSON response and returns the gene identifier, or null if not
+   * found. If the returned object_type is Gene, returns the id, if Transcript
+   * returns the Parent. If it is Translation (peptide identifier), then the
+   * Parent is the transcript identifier, so we redo the search with this value.
+   * 
+   * @param br
+   * @return
+   */
+  protected String parseGeneId(BufferedReader br)
   {
-    String parent = null;
+    String geneId = null;
     JSONParser jp = new JSONParser();
     try
     {
       JSONObject val = (JSONObject) jp.parse(br);
-      parent = val.get(attribute).toString();
-    } catch (ParseException | NullPointerException e)
+      String type = val.get(OBJECT_TYPE).toString();
+      if (OBJECT_TYPE_GENE.equalsIgnoreCase(type))
+      {
+        geneId = val.get(ID).toString();
+      }
+      else if (OBJECT_TYPE_TRANSCRIPT.equalsIgnoreCase(type))
+      {
+        geneId = val.get(PARENT).toString();
+      }
+      else if (OBJECT_TYPE_TRANSLATION.equalsIgnoreCase(type))
+      {
+        String transcriptId = val.get(PARENT).toString();
+        try
+        {
+          geneId = getGeneId(transcriptId);
+        } catch (StackOverflowError e)
+        {
+          /*
+           * unlikely data condition error!
+           */
+          System.err
+                  .println("** Ensembl lookup "
+                          + getUrl(transcriptId).toString()
+                          + " looping on Parent!");
+        }
+      }
+    } catch (ParseException | IOException e)
     {
       // ignore
     }
-    return parent;
+    return geneId;
   }
 
 }