JSON refactoring
[jalview.git] / src / jalview / ext / ensembl / EnsemblRestClient.java
index 5ebfcbf..b3113f9 100644 (file)
@@ -21,7 +21,9 @@
 package jalview.ext.ensembl;
 
 import jalview.bin.Cache;
-import jalview.bin.Jalview;
+import jalview.javascript.json.JSON;
+import jalview.util.JSONUtils;
+import jalview.util.Platform;
 import jalview.util.StringUtils;
 
 import java.io.BufferedReader;
@@ -29,6 +31,7 @@ import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.Reader;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.ProtocolException;
@@ -39,9 +42,7 @@ import java.util.Map;
 
 import javax.ws.rs.HttpMethod;
 
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
 
 /**
  * Base class for Ensembl REST service clients
@@ -189,7 +190,8 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    * @see http://rest.ensembl.org/documentation/info/ping
    * @return
    */
-  boolean checkEnsembl()
+  @SuppressWarnings("unchecked")
+boolean checkEnsembl()
   {
     BufferedReader br = null;
     String pingUrl = getDomain() + "/info/ping" + CONTENT_TYPE_JSON;
@@ -197,20 +199,17 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     {
       // note this format works for both ensembl and ensemblgenomes
       // info/ping.json works for ensembl only (March 2016)
-      URL ping = new URL(pingUrl);
-
+       
+       
+       
+       
       /*
        * expect {"ping":1} if ok
        * if ping takes more than 2 seconds to respond, treat as if unavailable
        */
-      br = getHttpResponse(ping, null, 2 * 1000);
-      if (br == null)
-      {
-        // error reponse status
-        return false;
-      }
-      JSONParser jp = new JSONParser();
-      JSONObject val = (JSONObject) jp.parse(br);
+      Map<String, Object> val = (Map<String, Object>) getJSON(new URL(pingUrl), null, 2 * 1000, MODE_MAP, null);
+      if (val == null)
+         return false;
       String pingString = val.get("ping").toString();
       return pingString != null;
     } catch (Throwable t)
@@ -233,37 +232,41 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     return false;
   }
 
-  /**
-   * 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 BufferedReader getSequenceReader(List<String> ids)
-          throws IOException
-  {
-    URL url = getUrl(ids);
-
-    BufferedReader reader = getHttpResponse(url, ids);
-    return reader;
-  }
-
-  /**
-   * Gets a reader to the HTTP response, using the default read timeout of 5
-   * minutes
-   * 
-   * @param url
-   * @param ids
-   * @return
-   * @throws IOException
-   */
-  protected BufferedReader getHttpResponse(URL url, List<String> ids)
-          throws IOException
-  {
-    return getHttpResponse(url, ids, DEFAULT_READ_TIMEOUT);
-  }
+  
+  protected final static int MODE_ARRAY    = 0;
+  protected final static int MODE_MAP      = 1;
+  protected final static int MODE_ITERATOR = 2;
+  
+//  /**
+//   * 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
+// * @throws ParseException 
+//   */
+//  protected Object getSequenceJSON(List<String> ids, int mode)
+//          throws IOException, ParseException
+//  {
+//    URL url = getUrl(ids);
+//    return getJSON(url, ids, -1, mode);
+//  }
+//
+//  /**
+//   * Gets a reader to the HTTP response, using the default read timeout of 5
+//   * minutes
+//   * 
+//   * @param url
+//   * @param ids
+//   * @return
+//   * @throws IOException
+//   */
+//  protected BufferedReader getHttpResponse(URL url, List<String> ids)
+//          throws IOException
+//  {
+//    return getHttpResponse(url, ids, DEFAULT_READ_TIMEOUT);
+//  }
 
   /**
    * Sends the HTTP request and gets the response as a reader. Returns null if
@@ -277,13 +280,19 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    * @return
    * @throws IOException
    */
-  protected BufferedReader getHttpResponse(URL url, List<String> ids,
+  private BufferedReader getHttpResponse(URL url, List<String> ids,
           int readTimeout) throws IOException
   {
+       if (readTimeout < 0)
+               readTimeout = DEFAULT_READ_TIMEOUT;
     int retriesLeft = MAX_RETRIES;
     HttpURLConnection connection = null;
     int responseCode = 0;
-
+        
+    if (Platform.isJS()) {
+         JSON.setAjax(url);
+    }
+        
     while (retriesLeft > 0)
     {
       connection = tryConnection(url, ids, readTimeout);
@@ -304,18 +313,21 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
        * note: a GET request for an invalid id returns an error code e.g. 415
        * but POST request returns 200 and an empty Fasta response 
        */
-      System.err.println("Response code " + responseCode + " for " + url);
+      System.err.println("Response code " + responseCode);// + " for " + url);
       return null;
     }
 
     InputStream response = connection.getInputStream();
+    
+    if (Platform.isJS()) {
+       return JSON.getJSONReader(response);
+    }
 
     // System.out.println(getClass().getName() + " took "
     // + (System.currentTimeMillis() - now) + "ms to fetch");
 
-    BufferedReader reader = null;
-    reader = new BufferedReader(new InputStreamReader(response, "UTF-8"));
-    return reader;
+    return new BufferedReader(new InputStreamReader(response, "UTF-8"));
   }
 
   /**
@@ -330,6 +342,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
           int readTimeout) throws IOException, ProtocolException
   {
     // System.out.println(System.currentTimeMillis() + " " + url);
+       
     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
 
     /*
@@ -466,26 +479,87 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     wr.close();
   }
 
+       /**
+        * Primary access point to parsed JSON data, including the call to retrieve and
+        * parsing.
+        * 
+        * @param url     request url; if null, getUrl(ids) will be used
+        * @param ids     optional; may be null
+        * @param msDelay -1 for default delay
+        * @param mode    map, array, or array iterator
+        * @param mapKey  an optional key for an outer map 
+        * @return                a Map, List, Iterator, or null
+        * @throws IOException
+        * @throws ParseException
+        * 
+        * @author Bob Hanson 2019
+        */
+  @SuppressWarnings("unchecked")
+  protected Object getJSON(URL url, List<String> ids, int msDelay, int mode, String mapKey) throws IOException, ParseException {
+
+       if (url == null)
+          url = getUrl(ids);
+       
+       Platform.timeCheck("EnsembleRestClient.getJSON0 " + url, Platform.TIME_MARK);
+       
+       Reader br = null;
+       try {
+      br = (url == null ? null : getHttpResponse(url, ids, msDelay));
+
+      Platform.timeCheck("EnsembleRestClient.getJSON1 parsing... ", Platform.TIME_MARK);
+       
+      Object ret = (br == null ? null : JSONUtils.parse(br));
+
+      Platform.timeCheck("EnsembleRestClient.getJSON2 ...done ", Platform.TIME_MARK);
+
+      if (ret != null && mapKey != null)
+           ret = ((Map<String, Object>) ret).get(mapKey);
+      if (ret == null) 
+      {
+        return null;
+      }
+      switch (mode) {
+      case MODE_ARRAY:
+      case MODE_MAP:
+       break;
+      case MODE_ITERATOR:
+       ret = ((List<Object>) ret).iterator();
+       break;
+      }
+      return ret;
+        
+    } finally
+    {
+      if (br != null)
+      {
+        try
+        {
+          br.close();
+        } catch (IOException e)
+        {
+        // ignore
+        }
+      }    
+    }
+  }
+
+
+
   /**
    * Fetches and checks Ensembl's REST version number
    * 
    * @return
    */
+  @SuppressWarnings("unchecked")
   private void checkEnsemblRestVersion()
   {
     EnsemblData info = domainData.get(getDomain());
 
-    JSONParser jp = new JSONParser();
-    URL url = null;
     try
     {
-      url = new URL(getDomain() + "/info/rest" + CONTENT_TYPE_JSON);
-      BufferedReader br = getHttpResponse(url, null);
-      if (br == null)
-      {
-        return;
-      }
-      JSONObject val = (JSONObject) jp.parse(br);
+      Map<String, Object> val = (Map<String, Object>) getJSON(new URL(getDomain() + "/info/rest" + CONTENT_TYPE_JSON), null, -1, MODE_MAP, null);
+      if (val == null)
+         return;
       String version = val.get("release").toString();
       String majorVersion = version.substring(0, version.indexOf("."));
       String expected = info.expectedRestVersion;
@@ -539,40 +613,21 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    * 
    * @return
    */
+  @SuppressWarnings("unchecked")
   private void checkEnsemblDataVersion()
   {
-    JSONParser jp = new JSONParser();
-    URL url = null;
-    BufferedReader br = null;
-
-    try
-    {
-      url = new URL(getDomain() + "/info/data" + CONTENT_TYPE_JSON);
-      br = getHttpResponse(url, null);
-      if (br != null)
-      {
-        JSONObject val = (JSONObject) jp.parse(br);
-        JSONArray versions = (JSONArray) val.get("releases");
-        domainData.get(getDomain()).dataVersion = versions.get(0)
-                .toString();
-      }
-    } catch (Throwable t)
-    {
-      System.err.println(
-              "Error checking Ensembl data version: " + t.getMessage());
-    } finally
-    {
-      if (br != null)
-      {
-        try
-        {
-          br.close();
-        } catch (IOException e)
-        {
-          // ignore
-        }
-      }
-    }
+    Map<String, Object> val;
+       try 
+       {
+         val = (Map<String, Object>) getJSON(
+                                 new URL(getDomain() + "/info/data" + CONTENT_TYPE_JSON), null, -1, MODE_MAP, null);
+         if (val == null)
+           return;
+         List<Object> versions = (List<Object>) val.get("releases");
+         domainData.get(getDomain()).dataVersion = versions.get(0).toString();
+       } catch (Throwable e) {//could be IOException | ParseException e) {
+         System.err.println("Error checking Ensembl data version: " + e.getMessage());
+       }
   }
 
   public String getEnsemblDataVersion()