}
}
// Start a TestListener
- if (aparser.contains("genomeapi"))
+ if (aparser.contains("startapi"))
{
try
{
- API gb = API.getInstance();
- Cache.info(gb.getName() + " started at "
+ API api = API.getInstance();
+ Cache.info(api.getName() + " started at "
+ HttpServer.getInstance().getUri().toString());
} catch (BindException e)
{
*
* @param e
*/
- protected void close_actionPerformed(ActionEvent e)
+ public void close_actionPerformed(ActionEvent e)
{
try
{
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
+import jalview.bin.Cache;
+
/**
*
* @author gmcarstairs
*/
System.err.println("Exception handling request "
+ request.getRequestURI() + " : " + t.getMessage());
+ Cache.error(t);
if (response.isCommitted())
{
/*
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
{
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 FetchSequenceEndpoint(this));
+ addEndpoint(new OpenAlignmentEndpoint(this));
+ addEndpoint(new HighlightSequenceEndpoint(this));
+ Cache.info("REMOVEME setting path to " + MY_PATH);
+ Cache.info("REMOVEME endpoints keys:");
+ for (String key : getEndpoints().keySet())
+ {
+ Cache.info("REMOVEME keyname=" + key);
+ }
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;
public abstract class Endpoint implements EndpointI
{
- private String name = null;
+ protected final String name;
- private API api = null;
-
- public void setName(String name)
- {
- this.name = name;
- }
+ protected API api;
public String getName()
{
return this.api;
}
+ public Endpoint(API api, final String name)
+ {
+ this.api = api;
+ this.name = name;
+ }
+
public abstract void processEndpoint(HttpServletRequest request,
HttpServletResponse response);
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import javax.servlet.http.HttpServletRequest;
public abstract class EndpointAsync extends Endpoint
{
- private String name = null;
+ public EndpointAsync(API api, final String name)
+ {
+ super(api, name);
+ }
+
+ protected String idExtension = null;
- private String idExtension = null;
+ protected String id = null;
- private String id = null;
+ protected CompletableFuture<Void> cf = null;
- private CompletableFuture<Void> cf = null;
+ protected Map<String, CompletableFuture<Void>> cfMap = new HashMap<>();
+
+ protected Map<String, String> stringMap = new HashMap<>();
protected void setCompletableFuture(CompletableFuture<Void> cf)
{
this.cf = cf;
+ if (getId() != null)
+ cfMap.put(getId(), cf);
}
protected CompletableFuture<Void> getCompletableFuture()
{
+ if (cf == null && getId() != null && cfMap.get(getId()) != null)
+ cf = cfMap.get(getId());
return this.cf;
}
- protected void setId(String idExtension)
+ protected void setId(String id)
{
- this.id = getName() + "::" + idExtension;
+ this.id = id;
+ }
+
+ protected void setIdExtension(String idExtension)
+ {
+ setId(getName() + "::" + idExtension);
}
protected String getId()
}
protected abstract void process(HttpServletRequest request,
- HttpServletResponse response);
+ HttpServletResponse response, final Map<String, String> finalMap);
protected void finalise(HttpServletRequest request,
HttpServletResponse response)
// can be Overridden
}
- protected void passCompletableFuture()
- {
- // Override this if you want to use an existing CompletableFuture
- }
-
@Override
public void processEndpoint(HttpServletRequest request,
HttpServletResponse response)
{
+ // subclass method
+ Cache.info("**************REMOVEME about to run initialise()");
initialise(request, response);
- final String id = getId();
- if (checkStatus(request, response))
+ Cache.info("**************REMOVEME about to run checkStatus()");
+ if (checkStatus(request, response, Status.STARTED))
+ {
+ returnStatus(response);
return;
+ }
- passCompletableFuture();
+ Cache.info(
+ "**************REMOVEME about to run getCompletableFuture()");
if (getCompletableFuture() == null)
{
+ final Map<String, String> finalMap = stringMap;
setCompletableFuture(CompletableFuture.runAsync(() -> {
- this.process(request, response);
+ // subclass method
+ this.process(request, response, finalMap);
}));
}
+ else
+ {
+ Cache.info(
+ "####################REMOVEME CompletableFuture cf is already set cf="
+ + cf);
+ }
+ Cache.info(
+ "####################REMOVEME about to run finaliseCompletableFuture()");
finaliseCompletableFuture();
+ // subclass method
finalise(request, response);
+ Cache.info("REMOVEME about to run returnStatus");
returnStatus(response);
+ Cache.info("REMOVEME about to change status for id=" + getId());
changeStatus(Status.IN_PROGRESS);
+ Cache.info("REMOVEME now changed status for id=" + getId()
+ + " to status=" + getStatus());
+ }
+
+ protected void atEnd()
+ {
}
/*
protected String setId(HttpServletRequest request, String extension)
{
String idString = request.getParameter("id");
+ Cache.info("REMOVEME setting extension=" + extension);
+ Cache.info("REMOVEME idString=" + idString);
if (idString == null)
{
- setId(extension);
- idString = getId();
+ setIdExtension(extension);
+ Cache.info("REMOVEME id now " + getId());
+ }
+ else
+ {
+ setId(idString);
}
- return idString;
+ return getId();
}
protected void changeStatus(Status status)
{
String id = getId();
// don't change a job's status if it has finished or died
- if (API.getStatusMap().get(id) == Status.FINISHED
- || API.getStatusMap().get(id) == Status.ERROR)
+ if (getStatus() == Status.FINISHED || getStatus() == Status.ERROR)
return;
- API.getStatusMap().put(id, status);
+ api.getStatusMap().put(id, status);
}
protected Status getStatus()
{
- return API.getStatusMap().get(getId());
+ return api.getStatusMap().get(getId());
}
protected void returnStatus(HttpServletResponse response)
{
PrintWriter writer = response.getWriter();
if (id != null)
+ {
writer.write("id=" + id + "\n");
- if (API.getRequestMap().get(id) != null)
+ Cache.info("REMOVEME returnStatus id=" + id);
+ }
+ if (api.getRequestMap().get(id) != null)
+ {
writer.write(
- "request=" + API.getRequestMap().get(id).toString() + "\n");
- if (API.getStatusMap().get(id) != null)
+ "request=" + api.getRequestMap().get(id).toString() + "\n");
+ Cache.info("REMOVEME returnStatus request="
+ + api.getRequestMap().get(id).toString());
+ }
+ if (getStatus() != null)
{
- if (API.getStatusMap().get(id) == Status.ERROR)
+ if (getStatus() == Status.ERROR)
+ {
response.setStatus(500);
- writer.write(
- "status=" + API.getStatusMap().get(id).toString() + "\n");
+ Cache.info("REMOVEME returnStatus setting HTTP status to " + 500);
+ }
+ writer.write("status=" + getStatus().toString() + "\n");
+ Cache.info(
+ "REMOVEME returnStatus status=" + getStatus().toString());
+ }
+ if (getCompletableFuture() != null)
+ {
+ boolean isDone = getCompletableFuture().isDone();
+ boolean isError = getCompletableFuture().isCompletedExceptionally();
+ writer.write("cf.isDone=" + isDone + "\n");
+ writer.write("cf.isError=" + isError + "\n");
+ Cache.info("REMOVEME returnStatus cf.isDone=" + isDone);
+ Cache.info("REMOVEME returnStatus cf.isError=" + isDone);
}
} catch (IOException e)
{
protected boolean checkStatus(HttpServletRequest request,
HttpServletResponse response)
{
+ return checkStatus(request, response, null);
+ }
+
+ protected boolean checkStatus(HttpServletRequest request,
+ HttpServletResponse response, Status set)
+ {
String id = getId();
- Status status = API.getStatusMap().get(id);
+ Cache.info("REMOVEME checkStatus id=" + id);
+ Status status = getStatus();
if (status == null)
{
- API.getStatusMap().put(id, Status.STARTED);
- API.getRequestMap().put(id, request.getRequestURI());
+ Cache.info("REMOVEME checkStatus status is " + null);
+ if (set != null)
+ changeStatus(set);
+ api.getRequestMap().put(id, request.getRequestURI());
+ return false;
}
else
{
- returnStatus(response);
+ Cache.info("REMOVEME checkStatus status=" + status.toString());
return true;
}
- return false;
}
protected void finaliseCompletableFuture()
{
String id = getId();
+ Cache.info("######################REMOVEME setting whenComplete on cf");
cf.whenComplete((Void, e) -> {
if (e != null)
{
{
Cache.info("Endpoint job " + id + " completed successfully");
changeStatus(Status.FINISHED);
+ atEnd();
}
});
}
package jalview.rest;
+import java.util.Map;
+
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import jalview.bin.Cache;
import jalview.gui.Desktop;
import jalview.gui.SequenceFetcher;
import jalview.util.DBRefUtils;
public class FetchSequenceEndpoint extends EndpointAsync
{
- protected String name = "fetchsequence";
+ public FetchSequenceEndpoint(API api)
+ {
+ super(api, name);
+ }
+
+ protected static final String name = "fetchsequence";
+
+ private SequenceFetcher sf;
@Override
protected void initialise(HttpServletRequest request,
HttpServletResponse response)
{
- // note that endpointName should always be "fetchsequence"
-
String[] parameters = getEndpointPathParameters(request);
// check we can run fetchsequence
return;
String db = DBRefUtils.getCanonicalName(dbName);
+ Cache.info("REMOVEME dbName=" + dbName + ", db=" + db);
Desktop desktop = Desktop.instance;
- SequenceFetcher sf = new SequenceFetcher(desktop, db, dbId);
+ sf = new SequenceFetcher(desktop, db, dbId);
setCompletableFuture(sf.ok_actionPerformed(true));
+ Cache.info("REMOVEME got CompletableFuture cf=" + cf);
}
protected void process(HttpServletRequest request,
- HttpServletResponse response)
+ HttpServletResponse response, Map<String, String> map)
{
// all the work being done by the SequenceFetcher!
+ Cache.warn("THIS SHOULD NOT BE RUN");
+ }
+
+ protected void atEnd()
+ {
+ sf.close_actionPerformed(null);
}
}
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jalview.gui.CutAndPasteTransfer;
import jalview.gui.Desktop;
-public class OpenSequenceEndpoint extends EndpointAsync
+public class OpenAlignmentEndpoint extends EndpointAsync
{
- protected String name = "opensequence";
+ public OpenAlignmentEndpoint(API api)
+ {
+ super(api, name);
+ }
+
+ protected static final String name = "openalignment";
private String fileString;
urlString = request.getParameter("url");
method = request.getMethod().toLowerCase();
dataString = request.getParameter("data");
+ Cache.info("REMOVEME dataString=" + dataString);
body = null;
post = method.equalsIgnoreCase("post");
data = dataString != null;
+ Cache.info("REMOVEME urlString=" + urlString);
if (post)
{
access = "post";
content = null;
}
+ stringMap.put("content", content);
+
setId(request, access + "::" + ref);
}
protected void process(HttpServletRequest request,
HttpServletResponse response)
{
+ process(request, response, null);
+ }
+
+ protected void process(HttpServletRequest request,
+ HttpServletResponse response, final Map<String, String> finalMap)
+ {
+ Cache.info("REMOVEME finalMap=" + finalMap);
+ String content = finalMap.get("content");
if (post || data)
{
+ Cache.info("REMOVEME content=" + content);
// Sequence file contents being posted
// use File -> Input Alignment -> from Textbox
CutAndPasteTransfer cap = new CutAndPasteTransfer();
public interface EndpointI
{
- public void setName(String name);
-
public String getName();
public void processEndpoint(HttpServletRequest request,
HttpServletResponse response);
+
}
- public interface Endpoint
+ public interface EndpointOld
{
public void processEndpoint(String endpointName,
HttpServletRequest request, HttpServletResponse response);
private boolean init = false;
// map of method names and method handlers
- private Map<String, Endpoint> endpoints = null;
+ private Map<String, EndpointI> endpoints = null;
+
+ protected Map<String, EndpointI> getEndpoints()
+ {
+ return endpoints;
+ }
/**
* Singleton instance of this class
return;
}
- String endpointName = getEndpointName(request);
+ String endpointName = getRequestedEndpointName(request);
+ Cache.info("REMOVEME endpointName=" + endpointName);
+ Cache.info("REMOVEME endpoints[" + endpointName + "]="
+ + endpoints.get(endpointName));
if (!endpoints.containsKey(endpointName)
|| endpoints.get(endpointName) == null)
{
response.setHeader("Cache-Control", "no-cache/no-store");
response.setHeader("Content-type", "text/plain");
- Endpoint ep = endpoints.get(endpointName);
- ep.processEndpoint(endpointName, request, response);
+ EndpointI ep = endpoints.get(endpointName);
+ ep.processEndpoint(request, response);
return;
}
// e.g. registerHandler and addEndpoints
}
- protected boolean addEndpoint(String name, Endpoint ep)
+ protected boolean addEndpoint(EndpointI ep)
{
if (endpoints == null)
{
endpoints = new HashMap<>();
}
- endpoints.put(name, ep);
+ Cache.info("REMOVEME Adding Endpoint ep=" + ep);
+ Cache.info("REMOVEME Adding Endpoint ep.getName()=" + ep.getName());
+ Endpoint e = (Endpoint) ep;
+ Cache.info("REMOVEME Adding Endpoint e.name=" + e.name);
+ endpoints.put(ep.getName(), ep);
return true;
}
- protected String getEndpointName(HttpServletRequest request)
+ protected String getRequestedEndpointName(HttpServletRequest request)
{
String pathInfo = request.getPathInfo();
int slashpos = pathInfo.indexOf('/', 1);
HttpServletResponse response, String message)
{
response.setStatus(500); // set this to something better
- String endpointName = getEndpointName(request);
+ String endpointName = getRequestedEndpointName(request);
Cache.error(this.MY_NAME + " error: endpoint " + endpointName
+ " failed: '" + message + "'");
try