1 package jalview.ext.ensembl;
3 import jalview.io.FileParse;
5 import java.io.BufferedReader;
6 import java.io.DataOutputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.InputStreamReader;
10 import java.net.HttpURLConnection;
11 import java.net.MalformedURLException;
13 import java.util.List;
15 import javax.ws.rs.HttpMethod;
18 * Base class for Ensembl REST service clients
22 abstract class EnsemblRestClient extends EnsemblSequenceFetcher
24 protected final static String ENSEMBL_REST = "http://rest.ensembl.org";
26 protected static final String SEQUENCE_ID_URL = ENSEMBL_REST
29 // @see https://github.com/Ensembl/ensembl-rest/wiki/Output-formats
30 private static final String PING_URL = "http://rest.ensembl.org/info/ping.json";
32 private final static long RETEST_INTERVAL = 10000L; // 10 seconds
34 private static boolean ensemblRestAvailable = false;
36 private static long lastCheck = -1;
38 protected volatile boolean inProgress = false;
41 public boolean queryInProgress()
47 public StringBuffer getRawRecords()
53 * Returns the URL for the client http request
57 * @throws MalformedURLException
59 protected abstract URL getUrl(List<String> ids)
60 throws MalformedURLException;
63 * Returns true if client uses GET method, false if it uses POST
67 protected abstract boolean useGetRequest();
70 * Return the desired value for the Content-Type request header
75 * @see https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers
77 protected abstract String getRequestMimeType(boolean multipleIds);
80 * Return the desired value for the Accept request header
83 * @see https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers
85 protected abstract String getResponseMimeType();
88 * Tries to connect to Ensembl's REST 'ping' endpoint, and returns true if
89 * successful, else false
93 private boolean checkEnsembl()
97 URL ping = new URL(PING_URL);
98 HttpURLConnection conn = (HttpURLConnection) ping.openConnection();
99 int rc = conn.getResponseCode();
101 if (rc >= 200 && rc < 300)
105 } catch (Throwable t)
107 System.err.println("Error connecting to " + PING_URL + ": "
114 * returns a reader to a Fasta response from the Ensembl sequence endpoint
118 * @throws IOException
120 protected FileParse getSequenceReader(List<String> ids)
123 URL url = getUrl(ids);
125 BufferedReader reader = getHttpResponse(url, ids);
126 FileParse fp = new FileParse(reader, url.toString(), "HTTP_POST");
131 * Writes the HTTP request and gets the response as a reader.
135 * written as Json POST body if more than one
137 * @throws IOException
138 * if response code was not 200, or other I/O error
140 protected BufferedReader getHttpResponse(URL url, List<String> ids)
143 // long now = System.currentTimeMillis();
144 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
147 * POST method allows multiple queries in one request; it is supported for
148 * sequence queries, but not for overlap
150 boolean multipleIds = ids.size() > 1;// useGetRequest();
151 connection.setRequestMethod(multipleIds ? HttpMethod.POST
153 connection.setRequestProperty("Content-Type",
154 getRequestMimeType(multipleIds));
155 connection.setRequestProperty("Accept", getResponseMimeType());
157 connection.setUseCaches(false);
158 connection.setDoInput(true);
159 connection.setDoOutput(multipleIds);
163 writePostBody(connection, ids);
166 InputStream response = connection.getInputStream();
167 int responseCode = connection.getResponseCode();
169 if (responseCode != 200)
172 * note: a GET request for an invalid id returns an error code e.g. 415
173 * but POST request returns 200 and an empty Fasta response
175 throw new IOException(
176 "Response code was not 200. Detected response was "
179 // System.out.println(getClass().getName() + " took "
180 // + (System.currentTimeMillis() - now) + "ms to fetch");
182 BufferedReader reader = null;
183 reader = new BufferedReader(new InputStreamReader(response, "UTF-8"));
188 * Rechecks if Ensembl is responding, unless the last check was successful and
189 * the retest interval has not yet elapsed. Returns true if Ensembl is up,
194 protected boolean isEnsemblAvailable()
196 long now = System.currentTimeMillis();
197 boolean retest = now - lastCheck > RETEST_INTERVAL;
198 if (ensemblRestAvailable && !retest)
202 ensemblRestAvailable = checkEnsembl();
204 return ensemblRestAvailable;
208 * Constructs, writes and flushes the POST body of the request, containing the
209 * query ids in JSON format
213 * @throws IOException
215 protected void writePostBody(HttpURLConnection connection,
216 List<String> ids) throws IOException
219 StringBuilder postBody = new StringBuilder(64);
220 postBody.append("{\"ids\":[");
222 for (String id : ids)
226 postBody.append(",");
229 postBody.append("\"");
230 postBody.append(id.trim());
231 postBody.append("\"");
233 postBody.append("]}");
234 byte[] thepostbody = postBody.toString().getBytes();
235 connection.setRequestProperty("Content-Length",
236 Integer.toString(thepostbody.length));
237 DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
238 wr.write(thepostbody);