JAL-3851 allow multiple instances of Endpoints. Fixes to naming of IGV colour scheme
[jalview.git] / src / jalview / rest / RestHandler.java
index c4ada0e..1575cff 100644 (file)
@@ -24,6 +24,7 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
 import java.net.BindException;
 import java.util.HashMap;
 import java.util.Map;
@@ -73,13 +74,32 @@ public class RestHandler extends AbstractRequestHandler
   private boolean init = false;
 
   // map of method names and method handlers
-  private Map<String, EndpointI> endpoints = null;
+  private Map<String, AbstractEndpoint> endpoints = null;
 
-  protected Map<String, EndpointI> getEndpoints()
+  protected Map<String, AbstractEndpoint> getEndpoints()
   {
     return endpoints;
   }
 
+  protected AbstractEndpoint getNewEndpoint(String name)
+  {
+    if (getEndpoints() == null)
+    {
+      return null;
+    }
+    try
+    {
+      return getEndpoints().get(name).getClass()
+              .getDeclaredConstructor(API.class).newInstance(this);
+    } catch (InstantiationException | IllegalAccessException
+            | IllegalArgumentException | InvocationTargetException
+            | NoSuchMethodException | SecurityException e)
+    {
+      Console.debug("Could not instantiate new endpoint '" + name + "'", e);
+    }
+    return null;
+  }
+
   /**
    * Singleton instance of this class
    */
@@ -135,13 +155,21 @@ public class RestHandler extends AbstractRequestHandler
     // This "pointless" call to request.getInputStream() seems to preserve the
     // InputStream for use later in getRequestBody.
     request.getInputStream();
-    if (endpoints == null)
+
+    String remoteAddr = request.getRemoteAddr();
+    if (!("127.0.0.1".equals(remoteAddr) || "localhost".equals(remoteAddr)))
+    {
+      returnError(request, response, "Not authorised: " + remoteAddr,
+              HttpServletResponse.SC_UNAUTHORIZED);
+      return;
+    }
+    if (getEndpoints() == null)
     {
       final String queryString = request.getQueryString();
       final String reply = "REST not yet implemented; received "
               + request.getMethod() + ": " + request.getRequestURL()
               + (queryString == null ? "" : "?" + queryString);
-      System.out.println(reply);
+      Console.error(reply);
 
       response.setHeader("Cache-Control", "no-cache/no-store");
       response.setHeader("Content-type", "text/plain");
@@ -152,8 +180,8 @@ public class RestHandler extends AbstractRequestHandler
 
     String endpointName = getRequestedEndpointName(request);
 
-    if (!endpoints.containsKey(endpointName)
-            || endpoints.get(endpointName) == null)
+    if (!getEndpoints().containsKey(endpointName)
+            || getEndpoints().get(endpointName) == null)
     {
 
       response.setHeader("Cache-Control", "no-cache/no-store");
@@ -167,7 +195,7 @@ public class RestHandler extends AbstractRequestHandler
       ContextHandler ch = HttpServer.getInstance().getContextHandler(this);
       String base = HttpServer.getInstance().getUri().toString();
       String contextPath = ch == null ? "" : ch.getContextPath();
-      for (String key : endpoints.keySet())
+      for (String key : getEndpoints().keySet())
       {
         writer.write(base + contextPath + "/" + key + "\n");
       }
@@ -177,7 +205,7 @@ public class RestHandler extends AbstractRequestHandler
 
     response.setHeader("Cache-Control", "no-cache/no-store");
     response.setHeader("Content-type", "text/plain");
-    EndpointI ep = endpoints.get(endpointName);
+    EndpointI ep = getNewEndpoint(endpointName);
     ep.processEndpoint(request, response);
 
     return;
@@ -209,15 +237,14 @@ public class RestHandler extends AbstractRequestHandler
     // e.g. registerHandler and addEndpoints
   }
 
-  protected boolean addEndpoint(EndpointI ep)
+  protected void addEndpoint(AbstractEndpoint ep)
   {
-    if (endpoints == null)
+    if (getEndpoints() == null)
     {
       endpoints = new HashMap<>();
     }
-    AbstractEndpoint e = (AbstractEndpoint) ep;
     endpoints.put(ep.getPath(), ep);
-    return true;
+    Console.debug("REST API, added endpoint '" + ep.getPath() + "'");
   }
 
   protected String getRequestedEndpointName(HttpServletRequest request)
@@ -228,18 +255,17 @@ public class RestHandler extends AbstractRequestHandler
             : pathInfo.substring(1);
   }
 
-  protected String[] getEndpointPathParameters(HttpServletRequest request)
+  protected void returnError(HttpServletRequest request,
+          HttpServletResponse response, String message)
   {
-    String pathInfo = request.getPathInfo();
-    int slashpos = pathInfo.indexOf('/', 1);
-    return slashpos < 1 ? null
-            : pathInfo.substring(slashpos + 1).split("/");
+    returnError(request, response, message,
+            HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
   }
 
   protected void returnError(HttpServletRequest request,
-          HttpServletResponse response, String message)
+          HttpServletResponse response, String message, int statusCode)
   {
-    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+    response.setStatus(statusCode);
     String endpointName = getRequestedEndpointName(request);
     Console.error(getName() + " error: endpoint " + endpointName
             + " failed: '" + message + "'");
@@ -277,7 +303,7 @@ public class RestHandler extends AbstractRequestHandler
     StringBuilder sb = new StringBuilder();
     BufferedReader reader = null;
     Console.debug("REQUEST=" + request.toString());
-    Console.debug("REQUEST.Content-Lenggth=" + request.getContentLength());
+    Console.debug("REQUEST.Content-Length=" + request.getContentLength());
     try
     {
       reader = request.getReader();
@@ -285,8 +311,6 @@ public class RestHandler extends AbstractRequestHandler
     } catch (IllegalStateException e)
     {
       ServletInputStream is = request.getInputStream();
-      Console.debug("INPUTSTREAM "
-              + (is.isFinished() ? "FINISHED" : "NOT FINISHED"));
       reader = new BufferedReader(new InputStreamReader(is));
       Console.debug("Using getInputStream()");
     }