JAL-3785 renaming, adding to interface, tidying
authorBen Soares <b.soares@dundee.ac.uk>
Fri, 3 Sep 2021 17:17:24 +0000 (18:17 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Fri, 3 Sep 2021 17:17:24 +0000 (18:17 +0100)
src/jalview/httpserver/HttpServer.java
src/jalview/rest/API.java
src/jalview/rest/AbstractEndpoint.java [moved from src/jalview/rest/Endpoint.java with 61% similarity]
src/jalview/rest/AbstractEndpointAsync.java [moved from src/jalview/rest/EndpointAsync.java with 83% similarity]
src/jalview/rest/FetchSequencesEndpoint.java [moved from src/jalview/rest/FetchSequenceEndpoint.java with 67% similarity]
src/jalview/rest/HighlightSequenceEndpoint.java
src/jalview/rest/InputAlignmentEndpoint.java [moved from src/jalview/rest/OpenAlignmentEndpoint.java with 74% similarity]
src/jalview/rest/RestHandler.java

index 397f1a8..057c714 100644 (file)
@@ -322,6 +322,17 @@ public class HttpServer
   }
 
   /**
+   * 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.
index e7b2ced..0bd3caa 100644 (file)
@@ -14,6 +14,8 @@ 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
@@ -43,8 +45,8 @@ public class API extends RestHandler
     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);
@@ -72,4 +74,9 @@ public class API extends RestHandler
   {
     return requestMap;
   }
+
+  protected static Map<String, Object> getObjectMap()
+  {
+    return objectMap;
+  }
 }
similarity index 61%
rename from src/jalview/rest/Endpoint.java
rename to src/jalview/rest/AbstractEndpoint.java
index e062564..2db0366 100644 (file)
@@ -10,15 +10,31 @@ import javax.servlet.http.HttpServletResponse;
 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()
@@ -26,10 +42,19 @@ public abstract class Endpoint implements EndpointI
     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,
@@ -51,7 +76,7 @@ public abstract class Endpoint implements EndpointI
           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
@@ -84,4 +109,20 @@ public abstract class Endpoint implements EndpointI
     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
similarity index 83%
rename from src/jalview/rest/EndpointAsync.java
rename to src/jalview/rest/AbstractEndpointAsync.java
index ff11db1..eb8280f 100644 (file)
@@ -12,11 +12,12 @@ import javax.servlet.http.HttpServletResponse;
 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;
@@ -27,7 +28,7 @@ public abstract class EndpointAsync extends Endpoint
 
   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)
   {
@@ -50,7 +51,7 @@ public abstract class EndpointAsync extends Endpoint
 
   protected void setIdExtension(String idExtension)
   {
-    setId(getName() + "::" + idExtension);
+    setId(getPath() + "::" + idExtension);
   }
 
   protected String getId()
@@ -72,7 +73,7 @@ public abstract class EndpointAsync extends Endpoint
     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,
@@ -96,10 +97,10 @@ public abstract class EndpointAsync extends Endpoint
 
     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();
@@ -139,12 +140,12 @@ public abstract class EndpointAsync extends Endpoint
     // 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)
@@ -157,10 +158,10 @@ public abstract class EndpointAsync extends Endpoint
       {
         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)
       {
@@ -191,7 +192,7 @@ public abstract class EndpointAsync extends Endpoint
     {
       if (set != null)
         changeStatus(set);
-      api.getRequestMap().put(id, request.getRequestURI());
+      getAPI().getRequestMap().put(id, request.getRequestURI());
       return false;
     }
     else
similarity index 67%
rename from src/jalview/rest/FetchSequenceEndpoint.java
rename to src/jalview/rest/FetchSequencesEndpoint.java
index 8bf54c2..71734c6 100644 (file)
@@ -10,14 +10,20 @@ import jalview.gui.Desktop;
 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;
 
@@ -25,15 +31,11 @@ public class FetchSequenceEndpoint extends EndpointAsync
   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];
@@ -48,7 +50,7 @@ public class FetchSequenceEndpoint extends EndpointAsync
     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!
index 556d45b..3f63ebb 100644 (file)
@@ -3,26 +3,29 @@ package jalview.rest;
 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(",");
similarity index 74%
rename from src/jalview/rest/OpenAlignmentEndpoint.java
rename to src/jalview/rest/InputAlignmentEndpoint.java
index 7e4b472..fd73b2d 100644 (file)
@@ -17,14 +17,20 @@ import jalview.bin.Cache;
 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;
 
@@ -32,19 +38,17 @@ public class OpenAlignmentEndpoint extends EndpointAsync
 
   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,
@@ -53,12 +57,12 @@ public class OpenAlignmentEndpoint extends EndpointAsync
     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
@@ -72,7 +76,7 @@ public class OpenAlignmentEndpoint extends EndpointAsync
       }
       // for ref see md5 later
     }
-    else if (data)
+    else if (hasData)
     {
       access = "data";
       // for ref see md5 later
@@ -97,9 +101,11 @@ public class OpenAlignmentEndpoint extends EndpointAsync
 
     // 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");
@@ -116,22 +122,20 @@ public class OpenAlignmentEndpoint extends EndpointAsync
       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
index 39fe26a..0c95354 100644 (file)
@@ -30,8 +30,11 @@ import java.util.Map;
 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
@@ -46,8 +49,14 @@ public class RestHandler extends AbstractRequestHandler
 
   public interface EndpointI
   {
+    public String getPath();
+
     public String getName();
 
+    public String getParameters();
+
+    public String getDescription();
+
     public void processEndpoint(HttpServletRequest request,
             HttpServletResponse response);
 
@@ -146,12 +155,21 @@ public class RestHandler extends AbstractRequestHandler
 
       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;
     }
 
@@ -195,8 +213,8 @@ public class RestHandler extends AbstractRequestHandler
     {
       endpoints = new HashMap<>();
     }
-    Endpoint e = (Endpoint) ep;
-    endpoints.put(ep.getName(), ep);
+    AbstractEndpoint e = (AbstractEndpoint) ep;
+    endpoints.put(ep.getPath(), ep);
     return true;
   }