JAL-6386 update slivka client for j2s compatibility
[jalview.git] / src / jalview / ws / slivkaws / SlivkaWSDiscoverer.java
index 1531e2d..7a41431 100644 (file)
@@ -1,16 +1,16 @@
 package jalview.ws.slivkaws;
 
+import jalview.bin.Cache;
 import jalview.gui.AlignFrame;
-import jalview.ws.WSMenuEntryProviderI;
+import jalview.ws.WSDiscovererI;
 import jalview.ws.api.ServiceWithParameters;
-import jalview.ws.jws2.MsaWSClient;
 import jalview.ws.jws2.PreferredServiceRegistry;
-import jalview.ws.jws2.SequenceAnnotationWSClient;
 
+import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
-import java.io.IOError;
 import java.io.IOException;
-import java.net.URISyntaxException;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -19,21 +19,18 @@ import javax.swing.JMenu;
 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
 
-public class SlivkaWSDiscoverer implements Runnable, WSMenuEntryProviderI
+public class SlivkaWSDiscoverer implements WSDiscovererI
 {
+  private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS";
+
+  private static final String COMPBIO_SLIVKA = "https://www.compbio.dundee.ac.uk/slivka/";
+
   private static SlivkaWSDiscoverer instance = null;
 
-  private SlivkaClient slivkaClient;
+  private List<ServiceWithParameters> services = List.of();
 
   private SlivkaWSDiscoverer()
   {
-    try
-    {
-      slivkaClient = new SlivkaClient("localhost", 4954);
-    } catch (URISyntaxException e)
-    {
-      throw new RuntimeException(e);
-    }
   }
 
   public static SlivkaWSDiscoverer getInstance()
@@ -45,39 +42,8 @@ public class SlivkaWSDiscoverer implements Runnable, WSMenuEntryProviderI
     return instance;
   }
 
-  private void addMsaServiceClient(JMenu alignmentMenu,
-          SlivkaService service, AlignFrame alignFrame)
-  {
-    SlivkaMsaServiceInstance instance = new SlivkaMsaServiceInstance(
-            slivkaClient, service);
-    MsaWSClient client = new MsaWSClient();
-    client.attachWSMenuEntry(alignmentMenu, instance, alignFrame);
-    alignmentMenu.addSeparator();
-  }
-
-  private void addDisorderServiceClient(JMenu disorderMenu,
-          SlivkaService service, AlignFrame alignFrame)
-  {
-    SlivkaAnnotationServiceInstance serviceInstance = new SlivkaAnnotationServiceInstance(
-            slivkaClient, service, false);
-
-    SequenceAnnotationWSClient client = new SequenceAnnotationWSClient();
-    client.attachWSMenuEntry(disorderMenu, serviceInstance, alignFrame);
-    disorderMenu.addSeparator();
-  }
-
-  private void addConservationServiceClient(JMenu conservationMenu,
-          SlivkaService service, AlignFrame alignFrame)
-  {
-    SlivkaAnnotationServiceInstance serviceInstance = new SlivkaAnnotationServiceInstance(
-            slivkaClient, service, true);
-    SequenceAnnotationWSClient client = new SequenceAnnotationWSClient();
-    client.attachWSMenuEntry(conservationMenu, serviceInstance, alignFrame);
-    conservationMenu.addSeparator();
-  }
-
   private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
-          this);
+      this);
 
   @Override
   public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame)
@@ -91,47 +57,193 @@ public class SlivkaWSDiscoverer implements Runnable, WSMenuEntryProviderI
     slivkaMenu.add(disorderMenu);
     JMenu conservationMenu = new JMenu("Conservation");
     slivkaMenu.add(conservationMenu);
-    try
+    PreferredServiceRegistry.getRegistry().populateWSMenuEntry(services,
+        changeSupport, slivkaMenu, alignFrame, null);
+
+  }
+
+  volatile boolean ready = false;
+
+  volatile Thread discovererThread = null;
+
+  private class DiscovererThread extends Thread
+  {
+    private Thread oldThread;
+
+    DiscovererThread(Thread oldThread)
+    {
+      super();
+      this.oldThread = oldThread;
+    }
+
+    @Override
+    public void run()
     {
-      List<ServiceWithParameters> instances = new ArrayList<>();
-      for (SlivkaService service : slivkaClient.getServices())
+      if (oldThread != null)
       {
-        for (String classifier : service.classifiers)
+        oldThread.interrupt();
+        try
         {
-          if (classifier.contains("Multiple sequence alignment"))
-          {
-            instances.add(
-                    new SlivkaMsaServiceInstance(slivkaClient, service));
-            // addMsaServiceClient(alignmentMenu, service, alignFrame);
-          }
-          else if (classifier.contains("Protein sequence analysis"))
+          oldThread.join();
+        } catch (InterruptedException e)
+        {
+          return;
+        } finally
+        {
+          oldThread = null;
+        }
+      }
+      ready = false;
+      reloadServices();
+      ready = !isInterrupted();
+    }
+  }
+
+  Thread discoverer = null;
+
+  @Override
+  public Thread startDiscoverer(PropertyChangeListener changeListener)
+  {
+    changeSupport.addPropertyChangeListener(changeListener);
+    ready = false;
+    (discovererThread = new DiscovererThread(discovererThread)).start();
+    return discovererThread;
+  }
+
+  private void reloadServices()
+  {
+    Cache.log.info("Reloading Slivka services");
+    changeSupport.firePropertyChange("services", services, List.of());
+    ArrayList<ServiceWithParameters> instances = new ArrayList<>();
+
+    for (String url : getServiceUrls())
+    {
+      Cache.log.info(url);
+      SlivkaClient client;
+      client = new SlivkaClient(url);
+      try
+      {
+        for (SlivkaService service : client.getServices())
+        {
+          SlivkaWSInstance newinstance = null;
+          for (String classifier : service.classifiers)
           {
-            instances.add(new SlivkaAnnotationServiceInstance(slivkaClient,
-                    service, false));
-            // addDisorderServiceClient(disorderMenu, service, alignFrame);
+            if (classifier.contains("Multiple sequence alignment"))
+            {
+              newinstance = new SlivkaMsaServiceInstance(client, service);
+            }
+            if (classifier.contains("Protein sequence analysis")
+                && newinstance == null)
+            {
+              newinstance = new SlivkaAnnotationServiceInstance(client,
+                  service, false);
+            }
+            if (classifier
+                .contains("Sequence alignment analysis (conservation)"))
+            {
+              newinstance = new SlivkaAnnotationServiceInstance(client,
+                  service, true);
+            }
           }
-          else if (classifier
-                  .contains("Sequence alignment analysis (conservation)"))
+          if (newinstance != null)
           {
-            instances.add(new SlivkaAnnotationServiceInstance(slivkaClient,
-                    service, true));
-            // addConservationServiceClient(conservationMenu, service,
-            // alignFrame);
+            instances.add(newinstance);
           }
-
         }
+      } catch (IOException e)
+      {
+        continue;
       }
-      PreferredServiceRegistry.getRegistry().populateWSMenuEntry(instances,
-              changeSupport, slivkaMenu, alignFrame, null);
-    } catch (IOException e)
+    }
+
+    services = instances;
+    changeSupport.firePropertyChange("services", List.of(), services);
+
+    Cache.log.info("Slivka services reloading finished");
+  }
+
+  @Override
+  public List<ServiceWithParameters> getServices()
+  {
+    return services;
+  }
+
+  @Override
+  public boolean hasServices()
+  {
+    return ready == true && services.size() > 0;
+  }
+
+  @Override
+  public boolean isRunning()
+  {
+    return discovererThread == null || discovererThread.isAlive()
+        || discovererThread.getState() == Thread.State.NEW;
+  }
+
+  @Override
+  public void setServiceUrls(List<String> wsUrls)
+  {
+    if (wsUrls != null && !wsUrls.isEmpty())
     {
-      throw new IOError(e);
+      Cache.setProperty(SLIVKA_HOST_URLS, String.join(",", wsUrls));
     }
+    else
+    {
+      Cache.removeProperty(SLIVKA_HOST_URLS);
+    }
+  }
+
+  @Override
+  public List<String> getServiceUrls()
+  {
+    String surls = Cache.getDefault(SLIVKA_HOST_URLS, COMPBIO_SLIVKA);
+    String[] urls = surls.split(",");
+    ArrayList<String> valid = new ArrayList<>(urls.length);
+    for (String url : urls)
+    {
+      try
+      {
+        new URL(url);
+        valid.add(url);
+      } catch (MalformedURLException e)
+      {
+        Cache.log.warn("Problem whilst trying to make a URL from '"
+            + ((url != null) ? url : "<null>") + "'");
+        Cache.log.warn(
+            "This was probably due to a malformed comma separated list"
+                + " in the " + SLIVKA_HOST_URLS
+                + " entry of $(HOME)/.jalview_properties)");
+        Cache.log.debug("Exception was ", e);
+      }
+    }
+    return valid;
+  }
+
+  @Override
+  public boolean testServiceUrl(URL url)
+  {
+    return getServerStatusFor(url.toString()) == STATUS_OK;
   }
 
   @Override
-  public void run()
+  public int getServerStatusFor(String url)
   {
+    try
+    {
+      List<?> services = new SlivkaClient(url).getServices();
+      return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
+    } catch (IOException e)
+    {
+      Cache.log.error("Slivka could not retrieve services list", e);
+      return STATUS_INVALID;
+    }
+  }
 
+  @Override
+  public String getErrorMessages()
+  {
+    // TODO Auto-generated method stub
+    return "";
   }
 }