JAL-3076 fetch Ensembl sequence as JSON instead of Fasta
[jalview.git] / src / jalview / ext / ensembl / EnsemblRestClient.java
index c06d13e..e6b1264 100644 (file)
@@ -20,8 +20,6 @@
  */
 package jalview.ext.ensembl;
 
-import jalview.io.DataSourceType;
-import jalview.io.FileParse;
 import jalview.util.StringUtils;
 
 import java.io.BufferedReader;
@@ -43,8 +41,6 @@ import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.json.simple.parser.JSONParser;
 
-import com.stevesoft.pat.Regex;
-
 /**
  * Base class for Ensembl REST service clients
  * 
@@ -68,37 +64,27 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    * @see https://github.com/Ensembl/ensembl-rest/wiki/Change-log
    * @see http://rest.ensembl.org/info/rest?content-type=application/json
    */
-  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "5.0";
+  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "6.0";
 
-  private static final String LATEST_ENSEMBL_REST_VERSION = "5.0";
+  private static final String LATEST_ENSEMBL_REST_VERSION = "6.1";
 
   private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
 
-  private static Map<String, EnsemblInfo> domainData;
-
-  // @see https://github.com/Ensembl/ensembl-rest/wiki/Output-formats
-  private static final String PING_URL = "http://rest.ensembl.org/info/ping.json";
+  private static Map<String, EnsemblInfo> domainData = new HashMap<>();
 
   private final static long AVAILABILITY_RETEST_INTERVAL = 10000L; // 10 seconds
 
   private final static long VERSION_RETEST_INTERVAL = 1000L * 3600; // 1 hr
 
-  private static final Regex PROTEIN_REGEX = new Regex(
-          "(ENS)([A-Z]{3}|)P[0-9]{11}$");
-
-  private static final Regex TRANSCRIPT_REGEX = new Regex(
-          "(ENS)([A-Z]{3}|)T[0-9]{11}$");
-
-  private static final Regex GENE_REGEX = new Regex(
-          "(ENS)([A-Z]{3}|)G[0-9]{11}$");
+  protected static final String CONTENT_TYPE_JSON = "?content-type=application/json";
 
   static
   {
-    domainData = new HashMap<String, EnsemblInfo>();
-    domainData.put(ENSEMBL_REST,
-            new EnsemblInfo(ENSEMBL_REST, LATEST_ENSEMBL_REST_VERSION));
-    domainData.put(ENSEMBL_GENOMES_REST, new EnsemblInfo(
-            ENSEMBL_GENOMES_REST, LATEST_ENSEMBLGENOMES_REST_VERSION));
+    domainData.put(DEFAULT_ENSEMBL_BASEURL,
+            new EnsemblInfo(DEFAULT_ENSEMBL_BASEURL, LATEST_ENSEMBL_REST_VERSION));
+    domainData.put(DEFAULT_ENSEMBL_GENOMES_BASEURL,
+            new EnsemblInfo(
+            DEFAULT_ENSEMBL_GENOMES_BASEURL, LATEST_ENSEMBLGENOMES_REST_VERSION));
   }
 
   protected volatile boolean inProgress = false;
@@ -108,7 +94,21 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    */
   public EnsemblRestClient()
   {
-    this(ENSEMBL_REST);
+    super();
+
+    /*
+     * initialise domain info lazily
+     */
+    if (!domainData.containsKey(ensemblDomain))
+    {
+      domainData.put(ensemblDomain,
+              new EnsemblInfo(ensemblDomain, LATEST_ENSEMBL_REST_VERSION));
+    }
+    if (!domainData.containsKey(ensemblGenomesDomain))
+    {
+      domainData.put(ensemblGenomesDomain, new EnsemblInfo(
+              ensemblGenomesDomain, LATEST_ENSEMBLGENOMES_REST_VERSION));
+    }
   }
 
   /**
@@ -121,42 +121,6 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     setDomain(d);
   }
 
-  /**
-   * Answers true if the query matches the regular expression pattern for an
-   * Ensembl transcript stable identifier
-   * 
-   * @param query
-   * @return
-   */
-  public boolean isTranscriptIdentifier(String query)
-  {
-    return query == null ? false : TRANSCRIPT_REGEX.search(query);
-  }
-
-  /**
-   * Answers true if the query matches the regular expression pattern for an
-   * Ensembl protein stable identifier
-   * 
-   * @param query
-   * @return
-   */
-  public boolean isProteinIdentifier(String query)
-  {
-    return query == null ? false : PROTEIN_REGEX.search(query);
-  }
-
-  /**
-   * Answers true if the query matches the regular expression pattern for an
-   * Ensembl gene stable identifier
-   * 
-   * @param query
-   * @return
-   */
-  public boolean isGeneIdentifier(String query)
-  {
-    return query == null ? false : GENE_REGEX.search(query);
-  }
-
   @Override
   public boolean queryInProgress()
   {
@@ -187,22 +151,28 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   protected abstract boolean useGetRequest();
 
   /**
-   * Return the desired value for the Content-Type request header
-   * 
-   * @param multipleIds
+   * Returns the desired value for the Content-Type request header. Default is
+   * application/json, override if required to vary this.
    * 
    * @return
    * @see https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers
    */
-  protected abstract String getRequestMimeType(boolean multipleIds);
+  protected String getRequestMimeType()
+  {
+    return "application/json";
+  }
 
   /**
-   * Return the desired value for the Accept request header
+   * Return the desired value for the Accept request header. Default is
+   * application/json, override if required to vary this.
    * 
    * @return
    * @see https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers
    */
-  protected abstract String getResponseMimeType();
+  protected String getResponseMimeType()
+  {
+    return "application/json";
+  }
 
   /**
    * Checks Ensembl's REST 'ping' endpoint, and returns true if response
@@ -214,12 +184,12 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   boolean checkEnsembl()
   {
     BufferedReader br = null;
+    String pingUrl = getDomain() + "/info/ping" + CONTENT_TYPE_JSON;
     try
     {
       // note this format works for both ensembl and ensemblgenomes
       // info/ping.json works for ensembl only (March 2016)
-      URL ping = new URL(
-              getDomain() + "/info/ping?content-type=application/json");
+      URL ping = new URL(pingUrl);
 
       /*
        * expect {"ping":1} if ok
@@ -228,6 +198,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
       br = getHttpResponse(ping, null, 2 * 1000);
       if (br == null)
       {
+        // error reponse status
         return false;
       }
       JSONParser jp = new JSONParser();
@@ -237,7 +208,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     } catch (Throwable t)
     {
       System.err.println(
-              "Error connecting to " + PING_URL + ": " + t.getMessage());
+              "Error connecting to " + pingUrl + ": " + t.getMessage());
     } finally
     {
       if (br != null)
@@ -255,25 +226,20 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   }
 
   /**
-   * returns a reader to a Fasta response from the Ensembl sequence endpoint
+   * Returns a reader to a (Json) response from the Ensembl sequence endpoint.
+   * If the request failed the return value may be null.
    * 
    * @param ids
    * @return
    * @throws IOException
    */
-  protected FileParse getSequenceReader(List<String> ids) throws IOException
+  protected BufferedReader getSequenceReader(List<String> ids)
+          throws IOException
   {
     URL url = getUrl(ids);
 
     BufferedReader reader = getHttpResponse(url, ids);
-    if (reader == null)
-    {
-      // request failed
-      return null;
-    }
-    FileParse fp = new FileParse(reader, url.toString(),
-            DataSourceType.URL);
-    return fp;
+    return reader;
   }
 
   /**
@@ -365,8 +331,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     boolean multipleIds = ids != null && ids.size() > 1;
     connection.setRequestMethod(
             multipleIds ? HttpMethod.POST : HttpMethod.GET);
-    connection.setRequestProperty("Content-Type",
-            getRequestMimeType(multipleIds));
+    connection.setRequestProperty("Content-Type", getRequestMimeType());
     connection.setRequestProperty("Accept", getResponseMimeType());
 
     connection.setUseCaches(false);
@@ -506,9 +471,12 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     URL url = null;
     try
     {
-      url = new URL(
-              getDomain() + "/info/rest?content-type=application/json");
+      url = new URL(getDomain() + "/info/rest" + CONTENT_TYPE_JSON);
       BufferedReader br = getHttpResponse(url, null);
+      if (br == null)
+      {
+        return;
+      }
       JSONObject val = (JSONObject) jp.parse(br);
       String version = val.get("release").toString();
       String majorVersion = version.substring(0, version.indexOf("."));
@@ -571,8 +539,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 
     try
     {
-      url = new URL(
-              getDomain() + "/info/data?content-type=application/json");
+      url = new URL(getDomain() + "/info/data" + CONTENT_TYPE_JSON);
       br = getHttpResponse(url, null);
       if (br != null)
       {