JAL-4059 Added some more Platform.addJ2SDirectDatabaseCall web service URLs in static...
[jalview.git] / src / jalview / ws / ebi / EBIFetchClient.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.ws.ebi;
22
23 import java.io.BufferedReader;
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.net.HttpURLConnection;
29 import java.net.URL;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Locale;
33 import java.util.StringTokenizer;
34
35 import jalview.datamodel.DBRefSource;
36 import jalview.util.MessageManager;
37 import jalview.util.Platform;
38
39 /**
40  * DOCUMENT ME!
41  * 
42  * @author $author$
43  * @version $Revision$
44  */
45 public class EBIFetchClient
46 {
47   static
48   {
49     Platform.addJ2SDirectDatabaseCall("https://www.ebi.ac.uk/");
50   }
51
52   /**
53    * Creates a new EBIFetchClient object.
54    */
55   public EBIFetchClient()
56   {
57   }
58
59   /**
60    * DOCUMENT ME!
61    * 
62    * @return DOCUMENT ME!
63    */
64   public String[] getSupportedDBs()
65   {
66     // TODO - implement rest call for dbfetch getSupportedDBs
67     throw new Error(MessageManager.getString("error.not_yet_implemented"));
68   }
69
70   /**
71    * DOCUMENT ME!
72    * 
73    * @return DOCUMENT ME!
74    */
75   public String[] getSupportedFormats()
76   {
77     // TODO - implement rest call for dbfetch getSupportedFormats
78     throw new Error(MessageManager.getString("error.not_yet_implemented"));
79   }
80
81   /**
82    * DOCUMENT ME!
83    * 
84    * @return DOCUMENT ME!
85    */
86   public String[] getSupportedStyles()
87   {
88     // TODO - implement rest call for dbfetch getSupportedStyles
89     throw new Error(MessageManager.getString("error.not_yet_implemented"));
90   }
91
92   /**
93    * Send an HTTP fetch request to EBI and save the reply in a temporary file.
94    * 
95    * @param ids
96    *          the query formatted as db:query1;query2;query3
97    * @param format
98    *          the format wanted
99    * @param ext
100    *          for the temporary file to hold response (without separator)
101    * @return the file holding the response
102    * @throws OutOfMemoryError
103    */
104
105   public File fetchDataAsFile(String ids, String format, String ext)
106           throws OutOfMemoryError
107   {
108     File outFile = null;
109     try
110     {
111       outFile = File.createTempFile("jalview", "." + ext);
112       outFile.deleteOnExit();
113       fetchData(ids, format, outFile);
114       if (outFile.length() == 0)
115       {
116         outFile.delete();
117         return null;
118       }
119     } catch (Exception ex)
120     {
121     }
122     return outFile;
123   }
124
125   /**
126    * Fetches queries and either saves the response to a file or returns as
127    * string data
128    * 
129    * @param ids
130    * @param format
131    * @param outFile
132    * @return
133    * @throws OutOfMemoryError
134    */
135   String[] fetchData(String ids, String format, File outFile)
136           throws OutOfMemoryError
137   {
138     StringBuilder querystring = new StringBuilder(ids.length());
139     String database = parseIds(ids, querystring);
140     if (database == null)
141     {
142       jalview.bin.Console
143               .errPrintln("Invalid Query string : '" + ids + "'");
144       jalview.bin.Console
145               .errPrintln("Should be of form 'dbname:q1;q2;q3;q4'");
146       return null;
147     }
148
149     // note: outFile is currently always specified, so return value is null
150     String[] rslt = fetchBatch(querystring.toString(), database, format,
151             outFile);
152
153     return (rslt != null && rslt.length > 0 ? rslt : null);
154   }
155
156   /**
157    * Parses ids formatted as dbname:q1;q2;q3, returns the dbname and adds
158    * queries as comma-separated items to the querystring. dbname must be
159    * specified for at least one queryId. Returns null if a mixture of different
160    * dbnames is found (ignoring case).
161    * 
162    * @param ids
163    * @param queryString
164    * @return
165    */
166   static String parseIds(String ids, StringBuilder queryString)
167   {
168     String database = null;
169     StringTokenizer queries = new StringTokenizer(ids, ";");
170     boolean appending = queryString.length() > 0;
171     while (queries.hasMoreTokens())
172     {
173       String query = queries.nextToken();
174       int p = query.indexOf(':');
175       if (p > -1)
176       {
177         String db = query.substring(0, p);
178         if (database != null && !db.equalsIgnoreCase(database))
179         {
180           /*
181            * different databases mixed in together - invalid
182            */
183           return null;
184         }
185         database = db;
186         query = query.substring(p + 1);
187       }
188       queryString.append(appending ? "," : "");
189       queryString.append(query);
190       appending = true;
191     }
192     return database;
193   }
194
195   /**
196    * Fetches queries and either saves the response to a file or (if no file
197    * specified) returns as string data
198    * 
199    * @param ids
200    * @param database
201    * @param format
202    * @param outFile
203    * @return array of lines from EBI only if outFile is null (which it will not
204    *         be)
205    * @throws OutOfMemoryError
206    */
207   String[] fetchBatch(String ids, String database, String format,
208           File outFile) throws OutOfMemoryError
209   {
210     String url = buildUrl(ids, database, format);
211     InputStream is = null;
212     BufferedReader br = null;
213     try
214     {
215       URL rcall = new URL(url);
216       HttpURLConnection conn = (HttpURLConnection) rcall.openConnection();
217       int responseCode = conn.getResponseCode();
218       if (responseCode == 200)
219       {
220         is = conn.getInputStream();
221         if (outFile != null)
222         {
223           Platform.streamToFile(is, outFile);
224           return null;
225         }
226         br = new BufferedReader(new InputStreamReader(is));
227         String rtn;
228         List<String> arl = new ArrayList<>();
229         while ((rtn = br.readLine()) != null)
230         {
231           arl.add(rtn);
232         }
233         return (String[]) arl.toArray();
234       }
235       jalview.bin.Console.errPrintln(
236               "Warning: response code " + responseCode + " for " + url);
237     } catch (OutOfMemoryError er)
238     {
239       jalview.bin.Console.outPrintln("OUT OF MEMORY DOWNLOADING QUERY FROM "
240               + database + ":\n" + ids);
241       throw er;
242     } catch (Exception ex)
243     {
244       if (!ex.getMessage().startsWith(
245               "uk.ac.ebi.jdbfetch.exceptions.DbfNoEntryFoundException"))
246       {
247         jalview.bin.Console
248                 .errPrintln("Unexpected exception when retrieving from "
249                         + database + "\nQuery was : '" + ids + "'");
250         ex.printStackTrace(System.err);
251       }
252     } finally
253     {
254       if (is != null)
255       {
256         try
257         {
258           is.close();
259         } catch (IOException e)
260         {
261         }
262       }
263       if (br != null)
264       {
265         try
266         {
267           br.close();
268         } catch (IOException e)
269         {
270         }
271       }
272     }
273     return null;
274   }
275
276   /**
277    * Constructs the URL to fetch from
278    * 
279    * @param ids
280    * @param database
281    * @param format
282    * @return
283    */
284   static String buildUrl(String ids, String database, String format)
285   {
286     String url;
287     if (database.equalsIgnoreCase(DBRefSource.EMBL)
288             || database.equalsIgnoreCase(DBRefSource.EMBLCDS))
289     {
290       url = "https://www.ebi.ac.uk/ena/browser/api/embl/"
291               + ids.toLowerCase(Locale.ROOT) + "?download=true&gzip=true";
292     }
293     else
294     {
295       url = "https://www.ebi.ac.uk/Tools/dbfetch/dbfetch/"
296               + database.toLowerCase(Locale.ROOT) + "/"
297               + ids.toLowerCase(Locale.ROOT)
298               + (format != null ? "/" + format : "");
299     }
300     return url;
301   }
302 }