package jalview.rest;
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
import java.net.BindException;
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.xml.bind.DatatypeConverter;
-
-import jalview.bin.Cache;
-import jalview.gui.CutAndPasteTransfer;
-import jalview.gui.Desktop;
-import jalview.gui.SequenceFetcher;
-import jalview.util.DBRefUtils;
public class API extends RestHandler
{
private static Map<String, String> requestMap = new HashMap<>();
+ private static Map<String, Object> objectMap = new HashMap<>();
+
private static API instance = null;
public static API getInstance() throws BindException
super.init(MY_PATH);
// add endpoints here
- addEndpoint("fetchsequence", (String s, HttpServletRequest rq,
- HttpServletResponse rs) -> fetchSequence(s, rq, rs));
- addEndpoint("opensequence", (String s, HttpServletRequest rq,
- HttpServletResponse rs) -> openSequence(s, rq, rs));
- addEndpoint("highlight", (String s, HttpServletRequest rq,
- HttpServletResponse rs) -> highlight(s, rq, rs));
+ addEndpoint(new FetchSequencesEndpoint(this));
+ addEndpoint(new InputAlignmentEndpoint(this));
+ addEndpoint(new HighlightSequenceEndpoint(this));
+ addEndpoint(new SelectSequencesEndpoint(this));
+ addEndpoint(new GetCrossReferencesEndpoint(this));
+ addEndpoint(new HighlightGenomicRangeEndpoint(this));
setPath(MY_PATH);
this.registerHandler();
init = true;
}
- // for the "fetchsequence" endpoint
- private void fetchSequence(String endpointName,
- HttpServletRequest request, HttpServletResponse response)
- {
- // note that endpointName should always be "fetchsequence"
-
- String[] parameters = getEndpointPathParameters(request);
-
- // check we can run fetchsequence
- if (parameters.length < 2)
- {
- returnError(request, response,
- "requires 2 path parameters: dbname, ids");
- return;
- }
-
- String dbName = parameters[0];
- String dbId = parameters[1];
-
- // final for async later
- final String id = getId(request, endpointName, dbName + "::" + dbId);
- if (checkStatus(request, response, id))
- return;
-
- String db = DBRefUtils.getCanonicalName(dbName);
- Desktop desktop = Desktop.instance;
- SequenceFetcher sf = new SequenceFetcher(desktop, db, dbId);
- CompletableFuture<Void> cf = sf.ok_actionPerformed(true);
-
- setFuture(cf, id);
- returnStatus(response, id);
- changeStatus(id, Status.IN_PROGRESS);
- }
-
- // for the "opensequence" endpoint
- private void openSequence(String endpointName, HttpServletRequest request,
- HttpServletResponse response)
- {
- // note that endpointName should always be "opensequence"
- String fileString = request.getParameter("file");
- String urlString = request.getParameter("url");
- String method = request.getMethod().toLowerCase();
- String dataString = request.getParameter("data");
- String body = null;
- boolean post = method.equalsIgnoreCase("post");
- boolean data = dataString != null;
-
- String access = null;
- String ref = null;
- if (post)
- {
- access = "post";
- try
- {
- body = getRequestBody(request);
- } catch (IOException e)
- {
- returnError(request, response, "could not read POST body");
- Cache.debug(e);
- return;
- }
- // for ref see md5 later
- }
- else if (data)
- {
- access = "data";
- // for ref see md5 later
- }
- else if (fileString != null)
- {
- access = "file";
- ref = fileString;
- }
- else if (urlString != null)
- {
- access = "url";
- ref = urlString;
- }
-
- if (access == null)
- {
- returnError(request, response,
- "requires POST body or one of parameters 'data', 'file' or 'url'");
- return;
- }
-
- // final content used in Future
- final String content;
- if (post || data)
- {
- content = post ? body : dataString;
- try
- {
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- md5.update(content.getBytes());
- byte[] digest = md5.digest();
- ref = DatatypeConverter.printBase64Binary(digest).toLowerCase();
- } catch (NoSuchAlgorithmException e)
- {
- Cache.debug(e);
- }
- }
- else
- {
- content = null;
- }
-
- // final for async later
- final String id = getId(request, endpointName, access + "::" + ref);
- if (checkStatus(request, response, id))
- return;
-
- CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
- if (post || data)
- {
- // Sequence file contents being posted
- // use File -> Input Alignment -> from Textbox
- CutAndPasteTransfer cap = new CutAndPasteTransfer();
- cap.setText(content);
- cap.ok_actionPerformed(null);
- cap.cancel_actionPerformed(null);
- }
- else if (fileString != null)
- {
- // Sequence file on filesystem
- // use File -> Input Alignment -> From File
- URL url = null;
- File file = null;
- try
- {
- url = new URL(fileString);
- file = new File(url.toURI());
- } catch (MalformedURLException | URISyntaxException e)
- {
- returnError(request, response,
- "could not resolve file='" + fileString + "'");
- Cache.debug(e);
- return;
- }
- if (!file.exists())
- {
- returnError(request, response,
- "file='" + fileString + "' does not exist");
- return;
- }
- Desktop.instance.openFile(file, null, null);
- }
- else if (urlString != null)
- {
- boolean success = Desktop.instance.loadUrl(urlString, null);
- if (!success)
- {
- returnError(request, response,
- "url='" + urlString + "' could not be opened");
- return;
- }
- }
- });
-
- setFuture(cf, id);
- returnStatus(response, id);
- changeStatus(id, Status.IN_PROGRESS);
- }
-
- // for the "highlight" endpoint
- private void highlight(String endpointName, HttpServletRequest request,
- HttpServletResponse response)
- {
- String[] parameters = getEndpointPathParameters(request);
-
- // check we can run highlight
- if (parameters.length < 1)
- {
- returnError(request, response, "requires 1 path parameters: ranges");
- return;
- }
-
- String rangesString = parameters[0];
- String[] rangeStrings = rangesString.split(",");
- int[][] ranges = new int[rangeStrings.length][2];
- for (int i = 0; i < rangeStrings.length; i++)
- {
- String range = rangeStrings[i];
- try
- {
- int hyphenpos = range.indexOf('-');
- if (hyphenpos < 0)
- {
- ranges[i][0] = Integer.parseInt(range);
- ranges[i][1] = ranges[i][0];
- }
- else
- {
- ranges[i][0] = Integer.parseInt(range.substring(0, hyphenpos));
- ranges[i][1] = Integer.parseInt(range.substring(hyphenpos));
- }
- } catch (NumberFormatException nfe)
- {
- returnError(request, response,
- "couldn't parse ranges component '" + range + "'");
- return;
- }
- }
-
- }
-
- // template endpoint
- private void templateEndpoint(String endpointName,
- HttpServletRequest request, HttpServletResponse response)
- {
- // final for async later
- final String id = getId(request, endpointName,
- "some identifier for this endpoint request");
- if (checkStatus(request, response, id))
- return;
-
- CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
- // do stuff
- });
-
- setFuture(cf, id);
- returnStatus(response, id);
- changeStatus(id, Status.IN_PROGRESS);
- }
-
/*
* Shared methods below here
*/
return MY_PATH;
}
- private void changeStatus(String id, Status status)
- {
- // don't change a job's status if it has finished or died
- if (statusMap.get(id) == Status.FINISHED
- || statusMap.get(id) == Status.ERROR)
- return;
- statusMap.put(id, status);
- }
-
- private Status getStatus(String id)
- {
- return statusMap.get(id);
- }
-
- protected void returnStatus(HttpServletResponse response, String id)
- {
- try
- {
- PrintWriter writer = response.getWriter();
- if (id != null)
- writer.write("id=" + id + "\n");
- if (requestMap.get(id) != null)
- writer.write("request=" + requestMap.get(id).toString() + "\n");
- if (statusMap.get(id) != null)
- {
- if (statusMap.get(id) == Status.ERROR)
- response.setStatus(500);
- writer.write("status=" + statusMap.get(id).toString() + "\n");
- }
- } catch (IOException e)
- {
- Cache.debug(e);
- }
- }
-
- private String getId(HttpServletRequest request, String endpointName,
- String extra)
- {
- String idString = request.getParameter("id");
- if (idString == null)
- {
- idString = endpointName + "::" + extra;
- }
- return idString;
- }
-
- private boolean checkStatus(HttpServletRequest request,
- HttpServletResponse response, String id)
- {
- Status status = statusMap.get(id);
- if (status == null)
- {
- statusMap.put(id, Status.STARTED);
- requestMap.put(id, request.getRequestURI());
- }
- else
- {
- returnStatus(response, id);
- return true;
- }
- return false;
- }
-
- private void setFuture(CompletableFuture<Void> cf, String id)
- {
- cf.whenComplete((Void, e) -> {
- if (e != null)
- {
- Cache.error("API job " + id + " did not complete");
- Cache.debug(e);
- changeStatus(id, Status.ERROR);
- }
- else
- {
- Cache.info("API job " + id + " completed successfully");
- changeStatus(id, Status.FINISHED);
- }
- });
- }
-
protected static Map<String, Status> getStatusMap()
{
return statusMap;
{
return requestMap;
}
+
+ protected static Map<String, Object> getObjectMap()
+ {
+ return objectMap;
+ }
}