}
/**
+ * Gets the ContextHandler attached to this handler. Useful for obtaining the
+ * full path used to access a given handler.
+ *
+ * @param handler
+ */
+ public ContextHandler getContextHandler(AbstractRequestHandler handler)
+ {
+ return myHandlers.get(handler);
+ }
+
+ /**
* This sets the "suggested" port to use. It can only be called once before
* starting the HttpServer instance. After the server has actually started the
* port is set to the actual port being used and cannot be changed.
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(new FetchSequenceEndpoint(this));
- addEndpoint(new OpenAlignmentEndpoint(this));
+ addEndpoint(new FetchSequencesEndpoint(this));
+ addEndpoint(new InputAlignmentEndpoint(this));
addEndpoint(new HighlightSequenceEndpoint(this));
setPath(MY_PATH);
{
return requestMap;
}
+
+ protected static Map<String, Object> getObjectMap()
+ {
+ return objectMap;
+ }
}
import jalview.bin.Cache;
import jalview.rest.RestHandler.EndpointI;
-public abstract class Endpoint implements EndpointI
+public abstract class AbstractEndpoint implements EndpointI
{
- protected final String name;
+ private final String path;
- protected API api;
+ private API api;
- public String getName()
+ private final String name;
+
+ private final String parameters;
+
+ private final String description;
+
+ public AbstractEndpoint(API api, String path, String name,
+ String parameters, String description)
{
- return this.name;
+ this.api = api;
+ this.path = path;
+ this.name = name;
+ this.parameters = parameters;
+ this.description = description;
+ }
+
+ public String getPath()
+ {
+ return this.path;
}
protected API getAPI()
return this.api;
}
- public Endpoint(API api, final String name)
+ public String getName()
{
- this.api = api;
- this.name = name;
+ return this.name;
+ }
+
+ public String getParameters()
+ {
+ return this.parameters;
+ }
+
+ public String getDescription()
+ {
+ return this.description;
}
public abstract void processEndpoint(HttpServletRequest request,
HttpServletResponse response, String message)
{
response.setStatus(500); // set this to something better
- String endpointName = getName();
+ String endpointName = getPath();
Cache.error(getAPI().getName() + " error: endpoint " + endpointName
+ " failed: '" + message + "'");
try
return sb.toString();
}
+ protected boolean checkParameters(HttpServletRequest request,
+ HttpServletResponse response, int i)
+ {
+ String[] parameters = getEndpointPathParameters(request);
+
+ // check we can run fetchsequence
+ if (parameters.length < i)
+ {
+ returnError(request, response,
+ "requires parameters:" + getParameters() + "\n" + getName()
+ + ": " + getDescription());
+ return false;
+ }
+ return true;
+ }
+
}
\ No newline at end of file
import jalview.bin.Cache;
import jalview.rest.RestHandler.Status;
-public abstract class EndpointAsync extends Endpoint
+public abstract class AbstractEndpointAsync extends AbstractEndpoint
{
- public EndpointAsync(API api, final String name)
+ public AbstractEndpointAsync(API api, String path, String name,
+ String parameters, String description)
{
- super(api, name);
+ super(api, path, name, parameters, description);
}
protected String idExtension = null;
protected Map<String, CompletableFuture<Void>> cfMap = new HashMap<>();
- protected Map<String, String> stringMap = new HashMap<>();
+ protected Map<String, String> stringsPassedToProcessAsync = new HashMap<>();
protected void setCompletableFuture(CompletableFuture<Void> cf)
{
protected void setIdExtension(String idExtension)
{
- setId(getName() + "::" + idExtension);
+ setId(getPath() + "::" + idExtension);
}
protected String getId()
setId(request, null);
}
- protected abstract void process(HttpServletRequest request,
+ protected abstract void processAsync(HttpServletRequest request,
HttpServletResponse response, final Map<String, String> finalMap);
protected void finalise(HttpServletRequest request,
if (getCompletableFuture() == null)
{
- final Map<String, String> finalMap = stringMap;
+ final Map<String, String> finalMap = stringsPassedToProcessAsync;
setCompletableFuture(CompletableFuture.runAsync(() -> {
// subclass method
- this.process(request, response, finalMap);
+ this.processAsync(request, response, finalMap);
}));
}
finaliseCompletableFuture();
// don't change a job's status if it has finished or died
if (getStatus() == Status.FINISHED || getStatus() == Status.ERROR)
return;
- api.getStatusMap().put(id, status);
+ getAPI().getStatusMap().put(id, status);
}
protected Status getStatus()
{
- return api.getStatusMap().get(getId());
+ return getAPI().getStatusMap().get(getId());
}
protected void returnStatus(HttpServletResponse response)
{
writer.write("id=" + id + "\n");
}
- if (api.getRequestMap().get(id) != null)
+ if (getAPI().getRequestMap().get(id) != null)
{
- writer.write(
- "request=" + api.getRequestMap().get(id).toString() + "\n");
+ writer.write("request="
+ + getAPI().getRequestMap().get(id).toString() + "\n");
}
if (getStatus() != null)
{
{
if (set != null)
changeStatus(set);
- api.getRequestMap().put(id, request.getRequestURI());
+ getAPI().getRequestMap().put(id, request.getRequestURI());
return false;
}
else
import jalview.gui.SequenceFetcher;
import jalview.util.DBRefUtils;
-public class FetchSequenceEndpoint extends EndpointAsync
+public class FetchSequencesEndpoint extends AbstractEndpointAsync
{
- public FetchSequenceEndpoint(API api)
+ public FetchSequencesEndpoint(API api)
{
- super(api, name);
+ super(api, path, name, parameters, description);
}
- protected static final String name = "fetchsequence";
+ private static final String path = "fetchsequences";
+
+ private static final String name = "Fetch Sequences";
+
+ private static final String parameters = "<resource name>,<sequence ids>";
+
+ private static final String description = "Fetch sequences from online resource";
private SequenceFetcher sf;
protected void initialise(HttpServletRequest request,
HttpServletResponse response)
{
- String[] parameters = getEndpointPathParameters(request);
-
- // check we can run fetchsequence
- if (parameters.length < 2)
+ if (!checkParameters(request, response, 2))
{
- returnError(request, response,
- "requires 2 path parameters: dbname, ids");
return;
}
+ String[] parameters = getEndpointPathParameters(request);
String dbName = parameters[0];
String dbId = parameters[1];
setCompletableFuture(sf.ok_actionPerformed(true));
}
- protected void process(HttpServletRequest request,
+ protected void processAsync(HttpServletRequest request,
HttpServletResponse response, Map<String, String> map)
{
// all the work being done by the SequenceFetcher!
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-public class HighlightSequenceEndpoint extends Endpoint
+public class HighlightSequenceEndpoint extends AbstractEndpoint
{
public HighlightSequenceEndpoint(API api)
{
- super(api, name);
+ super(api, path, name, parameters, description);
}
- protected static final String name = "highlight";
+ protected static final String path = "highlight";
+
+ private static final String name = "Highlight positions";
+
+ private static final String parameters = "<sequence names>,<ranges>";
+
+ private static final String description = "Highlight the specified sequences with the specified range(s)";
public void processEndpoint(HttpServletRequest request,
HttpServletResponse response)
{
- String[] parameters = getEndpointPathParameters(request);
-
- // check we can run highlight
- if (parameters.length < 1)
+ if (!checkParameters(request, response, 2))
{
- returnError(request, response, "requires 1 path parameters: ranges");
return;
}
+ String[] parameters = getEndpointPathParameters(request);
String rangesString = parameters[0];
String[] rangeStrings = rangesString.split(",");
import jalview.gui.CutAndPasteTransfer;
import jalview.gui.Desktop;
-public class OpenAlignmentEndpoint extends EndpointAsync
+public class InputAlignmentEndpoint extends AbstractEndpointAsync
{
- public OpenAlignmentEndpoint(API api)
+ public InputAlignmentEndpoint(API api)
{
- super(api, name);
+ super(api, path, name, parameters, description);
}
- protected static final String name = "openalignment";
+ protected static final String path = "inputalignment";
+
+ private static final String name = "Input Alignment";
+
+ private static final String parameters = "POST <body> | GET ?[data=<data>|file=<fileURI>|url=<URL>]";
+
+ private static final String description = "Input an alignment from POST request body, GET request 'data' parameter, local file in 'file' parameter, url in 'url' parameter";
private String fileString;
private String method;
- private String dataString;
+ private String data;
private String body;
- private String content;
+ private boolean isPost;
- private boolean post;
+ private boolean hasData;
- private boolean data;
+ private String access = null;
- String access = null;
-
- String ref = null;
+ private String ref = null;
@Override
protected void initialise(HttpServletRequest request,
fileString = request.getParameter("file");
urlString = request.getParameter("url");
method = request.getMethod().toLowerCase();
- dataString = request.getParameter("data");
+ data = request.getParameter("data");
body = null;
- post = method.equalsIgnoreCase("post");
- data = dataString != null;
+ isPost = method.equalsIgnoreCase("post");
+ hasData = data != null;
- if (post)
+ if (isPost)
{
access = "post";
try
}
// for ref see md5 later
}
- else if (data)
+ else if (hasData)
{
access = "data";
// for ref see md5 later
// final content used in Future
final String content;
- if (post || data)
+ if (isPost || hasData)
{
- content = post ? body : dataString;
+ content = isPost ? body : data;
+ stringsPassedToProcessAsync.put("content", content); // needed as "final
+ // String" in process
try
{
MessageDigest md5 = MessageDigest.getInstance("MD5");
content = null;
}
- stringMap.put("content", content);
-
setId(request, access + "::" + ref);
}
protected void process(HttpServletRequest request,
HttpServletResponse response)
{
- process(request, response, null);
+ processAsync(request, response, null);
}
- protected void process(HttpServletRequest request,
+ protected void processAsync(HttpServletRequest request,
HttpServletResponse response, final Map<String, String> finalMap)
{
String content = finalMap.get("content");
- if (post || data)
+ if (isPost || hasData)
{
// Sequence file contents being posted
// use File -> Input Alignment -> from Textbox
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jetty.server.handler.ContextHandler;
+
import jalview.bin.Cache;
import jalview.httpserver.AbstractRequestHandler;
+import jalview.httpserver.HttpServer;
/**
* A simple handler to process (or delegate) HTTP requests on /jalview/rest
public interface EndpointI
{
+ public String getPath();
+
public String getName();
+ public String getParameters();
+
+ public String getDescription();
+
public void processEndpoint(HttpServletRequest request,
HttpServletResponse response);
response.setHeader("Cache-Control", "no-cache/no-store");
response.setHeader("Content-type", "text/plain");
- response.setStatus(400);
PrintWriter writer = response.getWriter();
writer.write(missingEndpointMessage == null
? "REST endpoint '" + endpointName + "' not defined"
: missingEndpointMessage);
+ writer.write("\n");
+ writer.write("Available endpoints are:\n");
+ ContextHandler ch = HttpServer.getInstance().getContextHandler(this);
+ String base = HttpServer.getInstance().getUri().toString();
+ String contextPath = ch == null ? "" : ch.getContextPath();
+ for (String key : endpoints.keySet())
+ {
+ writer.write(base + contextPath + "/" + key + "\n");
+ }
writer.close();
+ response.setStatus(400);
return;
}
{
endpoints = new HashMap<>();
}
- Endpoint e = (Endpoint) ep;
- endpoints.put(ep.getName(), ep);
+ AbstractEndpoint e = (AbstractEndpoint) ep;
+ endpoints.put(ep.getPath(), ep);
return true;
}