5dc3c94999aaf52dabcd79fd7686d7b9bbb07a31
[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 jalview.datamodel.DBRefSource;
24 import jalview.util.MessageManager;
25
26 import java.io.BufferedInputStream;
27 import java.io.BufferedReader;
28 import java.io.File;
29 import java.io.FileOutputStream;
30 import java.io.InputStream;
31 import java.io.InputStreamReader;
32 import java.net.HttpURLConnection;
33 import java.net.URL;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.StringTokenizer;
37
38 /**
39  * DOCUMENT ME!
40  * 
41  * @author $author$
42  * @version $Revision$
43  */
44 public class EBIFetchClient
45 {
46
47   /**
48    * Creates a new EBIFetchClient object.
49    */
50   public EBIFetchClient()
51   {
52   }
53
54   /**
55    * DOCUMENT ME!
56    * 
57    * @return DOCUMENT ME!
58    */
59   public String[] getSupportedDBs()
60   {
61     // TODO - implement rest call for dbfetch getSupportedDBs
62     throw new Error(MessageManager.getString("error.not_yet_implemented"));
63   }
64
65   /**
66    * DOCUMENT ME!
67    * 
68    * @return DOCUMENT ME!
69    */
70   public String[] getSupportedFormats()
71   {
72     // TODO - implement rest call for dbfetch getSupportedFormats
73     throw new Error(MessageManager.getString("error.not_yet_implemented"));
74   }
75
76   /**
77    * DOCUMENT ME!
78    * 
79    * @return DOCUMENT ME!
80    */
81   public String[] getSupportedStyles()
82   {
83     // TODO - implement rest call for dbfetch getSupportedStyles
84     throw new Error(MessageManager.getString("error.not_yet_implemented"));
85   }
86
87   /**
88    * Send an HTTP fetch request to EBI and save the reply in a temporary file.
89    * 
90    * @param ids
91    *          the query formatted as db:query1;query2;query3
92    * @param format
93    *          the format wanted
94    * @param extension
95    *          for the temporary file to hold response (without separator)
96    * @return the file holding the response
97    * @throws OutOfMemoryError
98    */
99
100   public File fetchDataAsFile(String ids, String format, String ext)
101           throws OutOfMemoryError
102   {
103     File outFile = null;
104     try
105     {
106       outFile = File.createTempFile("jalview", "." + ext);
107       outFile.deleteOnExit();
108       fetchData(ids, format, outFile);
109       if (outFile.length() == 0)
110       {
111         outFile.delete();
112         return null;
113       }
114     } catch (Exception ex)
115     {
116     }
117     return outFile;
118   }
119
120   /**
121    * Fetches queries and either saves the response to a file or returns as
122    * string data
123    * 
124    * @param ids
125    * @param format
126    * @param outFile
127    * @return
128    * @throws OutOfMemoryError
129    */
130   String[] fetchData(String ids, String format, File outFile)
131           throws OutOfMemoryError
132   {
133     StringBuilder querystring = new StringBuilder(ids.length());
134     String database = parseIds(ids, querystring);
135     if (database == null)
136     {
137       System.err.println("Invalid Query string : '" + ids + "'");
138       System.err.println("Should be of form 'dbname:q1;q2;q3;q4'");
139       return null;
140     }
141
142     // note: outFile is currently always specified, so return value is null
143     String[] rslt = fetchBatch(querystring.toString(), database, format,
144             outFile);
145
146     return (rslt != null && rslt.length > 0 ? rslt : null);
147   }
148
149   /**
150    * Parses ids formatted as dbname:q1;q2;q3, returns the dbname and adds
151    * queries as comma-separated items to the querystring. dbname must be
152    * specified for at least one queryId. Returns null if a mixture of different
153    * dbnames is found (ignoring case).
154    * 
155    * @param ids
156    * @param queryString
157    * @return
158    */
159   static String parseIds(String ids, StringBuilder queryString)
160   {
161     String database = null;
162     StringTokenizer queries = new StringTokenizer(ids, ";");
163     boolean appending = queryString.length() > 0;
164     while (queries.hasMoreTokens())
165     {
166       String query = queries.nextToken();
167       int p = query.indexOf(':');
168       if (p > -1)
169       {
170         String db = query.substring(0, p);
171         if (database != null && !db.equalsIgnoreCase(database))
172         {
173           /*
174            * different databases mixed in together - invalid
175            */
176           return null;
177         }
178         database = db;
179         query = query.substring(p + 1);
180       }
181       queryString.append(appending ? "," : "");
182       queryString.append(query);
183       appending = true;
184     }
185     return database;
186   }
187
188   /**
189    * Fetches queries and either saves the response to a file or (if no file
190    * specified) returns as string data
191    * 
192    * @param ids
193    * @param database
194    * @param format
195    * @param outFile
196    * @return
197    * @throws OutOfMemoryError
198    */
199   String[] fetchBatch(String ids, String database, String format,
200           File outFile) throws OutOfMemoryError
201   {
202     // long time = System.currentTimeMillis();
203     String url = buildUrl(ids, database, format);
204
205     try
206     {
207       URL rcall = new URL(url);
208
209       HttpURLConnection conn = (HttpURLConnection) rcall.openConnection();
210       int responseCode = conn.getResponseCode();
211       if (responseCode != 200)
212       {
213         System.err.println("Warning: response code " + responseCode
214                 + " for " + url);
215       }
216       InputStream is = new BufferedInputStream(conn.getInputStream());
217       if (outFile != null)
218       {
219         /**@j2sNative 
220          * if (outFile._isTemp) {
221          * outFile._bytes = is.$in.$in.buf;
222          * return null;
223          * }
224          */
225         FileOutputStream fio = new FileOutputStream(outFile);
226         byte[] bb = new byte[32 * 1024];
227         int l;
228         while ((l = is.read(bb)) > 0)
229         {
230           fio.write(bb, 0, l);
231         }
232         fio.close();
233         is.close();
234       }
235       else
236       {
237         BufferedReader br = new BufferedReader(new InputStreamReader(is));
238         String rtn;
239         List<String> arl = new ArrayList<String>();
240         while ((rtn = br.readLine()) != null)
241         {
242           arl.add(rtn);
243         }
244         return arl.toArray(new String[arl.size()]);
245       }
246     } catch (OutOfMemoryError er)
247     {
248       System.out.println("OUT OF MEMORY DOWNLOADING QUERY FROM " + database
249               + ":\n" + ids);
250       throw er;
251     } catch (Exception ex)
252     {
253       if (ex.getMessage().startsWith(
254               "uk.ac.ebi.jdbfetch.exceptions.DbfNoEntryFoundException"))
255       {
256         return null;
257       }
258       System.err.println("Unexpected exception when retrieving from "
259               + database + "\nQuery was : '" + ids + "'");
260       ex.printStackTrace(System.err);
261       return null;
262     } finally
263     {
264       // System.err.println("EBIFetch took " + (System.currentTimeMillis() -
265       // time) + " ms");
266     }
267     return null;
268   }
269
270   /**
271    * Constructs the URL to fetch from
272    * 
273    * @param ids
274    * @param database
275    * @param format
276    * @return
277    */
278   static String buildUrl(String ids, String database, String format)
279   {
280     String url;
281     if (database.equalsIgnoreCase(DBRefSource.EMBL)
282             || database.equalsIgnoreCase(DBRefSource.EMBLCDS))
283     {
284       url = "https://www.ebi.ac.uk/ena/data/view/" + ids.toLowerCase()
285               + (format != null ? "&" + format : "");
286     }
287     else
288     {
289       url = "https://www.ebi.ac.uk/Tools/dbfetch/dbfetch/"
290               + database.toLowerCase() + "/" + ids.toLowerCase()
291               + (format != null ? "/" + format : "");
292     }
293     return url;
294   }
295 }