From 127d0acaaa8080b632cec3293c94af089b07ce56 Mon Sep 17 00:00:00 2001 From: MMWarowny Date: Tue, 4 Feb 2020 11:26:36 +0000 Subject: [PATCH] JAL-3515 Extract core WSDiscoverer methods to a separate interface Creating WSDiscovererI interface helps to separating exposed methods from internal implementation details of Jws2Discoverer and implements the same functionality in SlivkaWSDiscoverer --- src/jalview/gui/AlignFrame.java | 26 +- src/jalview/gui/Desktop.java | 40 ++- src/jalview/gui/WsPreferences.java | 12 +- src/jalview/ws/WSDiscovererI.java | 34 +++ src/jalview/ws/jws2/Jws2Discoverer.java | 23 +- src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java | 261 ++++++++++++++------ .../jalview/ws/jabaws/AAConAnnotAndSettingsIO.java | 3 +- .../ws/jabaws/DisorderAnnotExportImport.java | 6 +- 8 files changed, 289 insertions(+), 116 deletions(-) create mode 100644 src/jalview/ws/WSDiscovererI.java diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index e66b8d1..9647e0f 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -102,6 +102,7 @@ import jalview.viewmodel.AlignmentViewport; import jalview.viewmodel.ViewportRanges; import jalview.ws.DBRefFetcher; import jalview.ws.DBRefFetcher.FetchFinishedListenerI; +import jalview.ws.WSDiscovererI; import jalview.ws.api.ServiceWithParameters; import jalview.ws.jws1.Discoverer; import jalview.ws.jws2.Jws2Discoverer; @@ -4414,9 +4415,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } // TODO: move into separate menu builder class. boolean new_sspred = false; + if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer(); + WSDiscovererI jws2servs = Jws2Discoverer.getDiscoverer(); if (jws2servs != null) { if (jws2servs.hasServices()) @@ -4443,30 +4445,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } } } - build_urlServiceMenu(me.webService); - - - // TODO Mateusz - follow pattern for adding web service - // JMenuItems for slivka-based services - SlivkaWSDiscoverer slivkaDiscoverer = SlivkaWSDiscoverer.getInstance(); - if (slivkaDiscoverer.hasServices()) + if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { - slivkaDiscoverer.attachWSMenuEntry(webService, me); - } else { - if (slivkaDiscoverer.isRunning()) + WSDiscovererI discoverer = SlivkaWSDiscoverer + .getInstance(); + if (discoverer != null) { + if (discoverer.hasServices()) + { + discoverer.attachWSMenuEntry(webService, me); + } + if (discoverer.isRunning()) { JMenuItem tm = new JMenuItem( "Still discovering Slivka Services"); tm.setEnabled(false); webService.add(tm); } - } } - + build_urlServiceMenu(me.webService); build_fetchdbmenu(webService); for (JMenu item : wsmenu) { diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 84e6aed..2402aef 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -45,6 +45,7 @@ import jalview.util.MessageManager; import jalview.util.Platform; import jalview.util.UrlConstants; import jalview.viewmodel.AlignmentViewport; +import jalview.ws.WSDiscovererI; import jalview.ws.params.ParamManager; import jalview.ws.utils.UrlDownloadClient; @@ -2534,7 +2535,7 @@ public class Desktop extends jalview.jbgui.GDesktop public void startServiceDiscovery(boolean blocking) { boolean alive = true; - Thread t0 = null, t1 = null, t2 = null; + Thread t0 = null, t1 = null, t2 = null, t3 = null; // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release if (true) { @@ -2552,14 +2553,14 @@ public class Desktop extends jalview.jbgui.GDesktop if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer() - .startDiscoverer(changeSupport); + t2 = startServiceDiscovery( + jalview.ws.jws2.Jws2Discoverer.getDiscoverer(), false); } - Thread t3 = null; + if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { // start slivka discovery - t3 = new Thread(jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance()); - t3.start(); + t3 = startServiceDiscovery( + jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance(), false); } if (blocking) { @@ -2571,13 +2572,31 @@ public class Desktop extends jalview.jbgui.GDesktop } catch (Exception e) { } + // FIXME: Condition should check the discoverer's isRunning rather than + // threads alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive()) - || (t3 != null && t3.isAlive()) - || (t0 != null && t0.isAlive()); + || (t3 != null && t3.isAlive()) || (t0 != null && t0.isAlive()); } } } + public Thread startServiceDiscovery(WSDiscovererI discoverer, + boolean blocking) + { + Thread thread = discoverer.startDiscoverer(changeSupport); + if (blocking) + { + try + { + thread.join(); + } catch (InterruptedException e) + { + e.printStackTrace(); + } + } + return thread; + } + /** * called to check if the service discovery process completed successfully. * @@ -2587,8 +2606,9 @@ public class Desktop extends jalview.jbgui.GDesktop { if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector) { - final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer() - .getErrorMessages(); + final WSDiscovererI discoverer = jalview.ws.jws2.Jws2Discoverer + .getDiscoverer(); + final String ermsg = discoverer.getErrorMessages(); if (ermsg != null) { if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true)) diff --git a/src/jalview/gui/WsPreferences.java b/src/jalview/gui/WsPreferences.java index 5186a26..51b40dd 100644 --- a/src/jalview/gui/WsPreferences.java +++ b/src/jalview/gui/WsPreferences.java @@ -23,6 +23,7 @@ package jalview.gui; import jalview.bin.Cache; import jalview.jbgui.GWsPreferences; import jalview.util.MessageManager; +import jalview.ws.WSDiscovererI; import jalview.ws.jws2.Jws2Discoverer; import jalview.ws.rest.RestServiceDescription; @@ -33,11 +34,11 @@ import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URL; +import java.util.ArrayList; import java.util.List; import java.util.Vector; import javax.swing.JLabel; -import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.JTextField; @@ -156,21 +157,22 @@ public class WsPreferences extends GWsPreferences String t = new String(""); switch (((Integer) status).intValue()) { - case 1: + case WSDiscovererI.STATUS_OK: // cb.setSelected(true); // cb.setBackground( c = Color.green; break; - case 0: + case WSDiscovererI.STATUS_NO_SERVICES: // cb.setSelected(true); // cb.setBackground( c = Color.lightGray; break; - case -1: + case WSDiscovererI.STATUS_INVALID: // cb.setSelected(false); // cb.setBackground( c = Color.red; break; + case WSDiscovererI.STATUS_UNKNOWN: default: // cb.setSelected(false); // cb.setBackground( @@ -485,7 +487,7 @@ public class WsPreferences extends GWsPreferences if (validate == JvOptionPane.OK_OPTION) { - if (Jws2Discoverer.testServiceUrl(foo)) + if (Jws2Discoverer.getDiscoverer().testServiceUrl(foo)) { return foo.toString(); } diff --git a/src/jalview/ws/WSDiscovererI.java b/src/jalview/ws/WSDiscovererI.java new file mode 100644 index 0000000..e5b94f0 --- /dev/null +++ b/src/jalview/ws/WSDiscovererI.java @@ -0,0 +1,34 @@ +package jalview.ws; + +import jalview.ws.api.ServiceWithParameters; + +import java.beans.PropertyChangeListener; +import java.net.URL; +import java.util.List; + +public interface WSDiscovererI extends WSMenuEntryProviderI +{ + public static final int STATUS_OK = 1; + public static final int STATUS_NO_SERVICES = 0; + public static final int STATUS_INVALID = -1; + public static final int STATUS_UNKNOWN = -2; + + public void setServiceUrls(List wsUrls); + + public List getServiceUrls(); + + public List getServices(); + + public boolean testServiceUrl(URL url); + + public int getServerStatusFor(String url); + + // TODO: should not return Thread but something generic providing isRunning method + public Thread startDiscoverer(PropertyChangeListener changeListener); + + public String getErrorMessages(); + + public boolean hasServices(); + + public boolean isRunning(); +} diff --git a/src/jalview/ws/jws2/Jws2Discoverer.java b/src/jalview/ws/jws2/Jws2Discoverer.java index d11174e..197d0ee 100644 --- a/src/jalview/ws/jws2/Jws2Discoverer.java +++ b/src/jalview/ws/jws2/Jws2Discoverer.java @@ -23,7 +23,7 @@ package jalview.ws.jws2; import jalview.bin.Cache; import jalview.gui.AlignFrame; import jalview.util.MessageManager; -import jalview.ws.WSMenuEntryProviderI; +import jalview.ws.WSDiscovererI; import jalview.ws.api.ServiceWithParameters; import jalview.ws.jws2.jabaws2.Jws2Instance; import jalview.ws.params.ParamDatastoreI; @@ -51,7 +51,7 @@ import compbio.ws.client.Services; * @author JimP * */ -public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI +public class Jws2Discoverer implements WSDiscovererI, Runnable { public static final String COMPBIO_JABAWS = "http://www.compbio.dundee.ac.uk/jabaws"; @@ -415,16 +415,19 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI return discoverer; } + @Override public boolean hasServices() { return !running && services != null && services.size() > 0; } + @Override public boolean isRunning() { return running; } + @Override public void setServiceUrls(List wsUrls) { if (wsUrls != null && !wsUrls.isEmpty()) @@ -451,6 +454,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI * * @return */ + @Override public List getServiceUrls() { if (testUrls != null) @@ -504,6 +508,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI return urls; } + @Override public Vector getServices() { return (services == null) ? new Vector<>() @@ -516,7 +521,8 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI * @param foo * @return */ - public static boolean testServiceUrl(URL foo) + @Override + public boolean testServiceUrl(URL foo) { try { @@ -564,6 +570,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI * @param changeSupport2 * @return new thread */ + @Override public Thread startDiscoverer(PropertyChangeListener changeSupport2) { /* if (restart()) @@ -645,6 +652,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI * @return a human readable report of any problems with the service URLs used * for discovery */ + @Override public String getErrorMessages() { if (!isRunning() && !isAborted()) @@ -693,21 +701,22 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI return null; } + @Override public int getServerStatusFor(String url) { if (validServiceUrls != null && validServiceUrls.contains(url)) { - return 1; + return STATUS_OK; } if (urlsWithoutServices != null && urlsWithoutServices.contains(url)) { - return 0; + return STATUS_NO_SERVICES; } if (invalidServiceUrls != null && invalidServiceUrls.contains(url)) { - return -1; + return STATUS_INVALID; } - return -2; + return STATUS_UNKNOWN; } /** diff --git a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java index 2b4a958..925cd55 100644 --- a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java +++ b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java @@ -1,14 +1,17 @@ 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.PreferredServiceRegistry; +import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; -import java.io.IOError; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URISyntaxException; +import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -17,21 +20,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 services = List.of(); private SlivkaWSDiscoverer() { - try - { - slivkaClient = new SlivkaClient("https://www.compbio.dundee.ac.uk/slivka"); - } catch (URISyntaxException e) - { - throw new RuntimeException(e); - } } public static SlivkaWSDiscoverer getInstance() @@ -43,111 +43,214 @@ public class SlivkaWSDiscoverer implements Runnable, WSMenuEntryProviderI return instance; } - /** - * TODO: tests needed for logic for determining type of each discovered - * service. Then reimplement this routine ! - * - * @return (MSA instances, one AAUI type instance, and the remaining all - * sequence analysis instances taking 1 sequence only) - */ - List getServiceInstances() + private PropertyChangeSupport changeSupport = new PropertyChangeSupport( + this); + + @Override + public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame) + { + JMenu slivkaMenu = new JMenu("Slivka"); + wsmenu.add(slivkaMenu); + + JMenu alignmentMenu = new JMenu("Sequence Alignment"); + slivkaMenu.add(alignmentMenu); + JMenu disorderMenu = new JMenu("Protein sequence analysis"); + slivkaMenu.add(disorderMenu); + JMenu conservationMenu = new JMenu("Conservation"); + slivkaMenu.add(conservationMenu); + PreferredServiceRegistry.getRegistry().populateWSMenuEntry(services, + changeSupport, slivkaMenu, alignFrame, null); + + } + + volatile boolean ready = false; + + volatile Thread discovererThread = null; + + private class DiscovererThread extends Thread { - List instances = new ArrayList<>(); - for (SlivkaService service : services) + private Thread oldThread; + + DiscovererThread(Thread oldThread) + { + super(); + this.oldThread = oldThread; + } + + @Override + public void run() { - ServiceWithParameters newinstance = null; - for (String classifier : service.classifiers) + if (oldThread != null) { - if (classifier.contains("Multiple sequence alignment")) + oldThread.interrupt(); + try { - // MSA services always overwrite - newinstance = new SlivkaMsaServiceInstance(slivkaClient, service); + oldThread.join(); + } catch (InterruptedException e) + { + return; + } finally + { + oldThread = null; } - if (classifier.contains("Protein sequence analysis")) + } + 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 instances = new ArrayList<>(); + + for (String url : getServiceUrls()) + { + Cache.log.info(url); + SlivkaClient client; + try + { + client = new SlivkaClient(url); + } catch (URISyntaxException e) + { + e.printStackTrace(); + continue; + } + try + { + for (SlivkaService service : client.getServices()) { - if (newinstance == null) + SlivkaWSInstance newinstance = null; + for (String classifier : service.classifiers) + { + if (classifier.contains("Multiple sequence alignment")) { - newinstance = (new SlivkaAnnotationServiceInstance( - slivkaClient, - - service, false)); + newinstance = new SlivkaMsaServiceInstance(client, service); } - } - - if (classifier + if (classifier.contains("Protein sequence analysis") + && newinstance == null) + { + newinstance = new SlivkaAnnotationServiceInstance(client, + service, false); + } + if (classifier .contains("Sequence alignment analysis (conservation)")) - { - // always overwrite other instances - newinstance = new SlivkaAnnotationServiceInstance(slivkaClient, + { + newinstance = new SlivkaAnnotationServiceInstance(client, service, true); + } + } + if (newinstance != null) + { + instances.add(newinstance); + } } - } - if (newinstance != null) + } catch (IOException e) { - instances.add(newinstance); + continue; } } - return instances; - } - private PropertyChangeSupport changeSupport = new PropertyChangeSupport( - this); + services = instances; + changeSupport.firePropertyChange("services", List.of(), services); + + Cache.log.info("Slivka services reloading finished"); + } @Override - public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame) + public List getServices() { - JMenu slivkaMenu = new JMenu("Slivka"); - wsmenu.add(slivkaMenu); - - JMenu alignmentMenu = new JMenu("Sequence Alignment"); - slivkaMenu.add(alignmentMenu); - JMenu disorderMenu = new JMenu("Protein sequence analysis"); - slivkaMenu.add(disorderMenu); - JMenu conservationMenu = new JMenu("Conservation"); - slivkaMenu.add(conservationMenu); - PreferredServiceRegistry.getRegistry().populateWSMenuEntry( - getServiceInstances(), - changeSupport, slivkaMenu, alignFrame, null); - + return services; } - Listservices=null; + @Override + public boolean hasServices() + { + return ready == true && services.size() > 0; + } - volatile boolean started = false, finished = false; + @Override + public boolean isRunning() + { + return discovererThread == null || discovererThread.isAlive() + || discovererThread.getState() == Thread.State.NEW; + } - Thread discoverer = null; @Override - public void run() + public void setServiceUrls(List wsUrls) { - discoverer = Thread.currentThread(); - started = true; - try + if (wsUrls != null && !wsUrls.isEmpty()) { - services = slivkaClient.getServices(); - } catch (IOException e) + Cache.setProperty(SLIVKA_HOST_URLS, String.join(",", wsUrls)); + } + else { - throw new IOError(e); + Cache.removeProperty(SLIVKA_HOST_URLS); } - finished = true; } - public static List getServices() + @Override + public List getServiceUrls() { - SlivkaWSDiscoverer us = getInstance(); - if (us.services == null) + String surls = Cache.getDefault(SLIVKA_HOST_URLS, COMPBIO_SLIVKA); + String[] urls = surls.split(","); + ArrayList valid = new ArrayList<>(urls.length); + for (String url : urls) { - us.run(); + try + { + new URL(url); + valid.add(url); + } catch (MalformedURLException e) + { + Cache.log.warn("Problem whilst trying to make a URL from '" + + ((url != null) ? url : "") + "'"); + 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 us.getServiceInstances(); + return valid; } - public boolean hasServices() + @Override + public boolean testServiceUrl(URL url) { - return finished == true && services != null && services.size() > 0; + return getServerStatusFor(url.toString()) == STATUS_OK; } - public boolean isRunning() + @Override + public int getServerStatusFor(String url) + { + try + { + List services = new SlivkaClient(url).getServices(); + return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK; + } catch (IOException | URISyntaxException e) + { + return STATUS_INVALID; + } + } + + @Override + public String getErrorMessages() { - return discoverer != null && discoverer.isAlive(); + // TODO Auto-generated method stub + return ""; } } diff --git a/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java b/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java index 2a6c3d0..5428acd 100644 --- a/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java +++ b/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java @@ -89,7 +89,8 @@ public class AAConAnnotAndSettingsIO } } - for (ServiceWithParameters svc : SlivkaWSDiscoverer.getServices()) + for (ServiceWithParameters svc : SlivkaWSDiscoverer.getInstance() + .getServices()) { if (svc.getNameURI().toLowerCase().contains("aacon")) { diff --git a/test/jalview/ws/jabaws/DisorderAnnotExportImport.java b/test/jalview/ws/jabaws/DisorderAnnotExportImport.java index 8454e03..fef2828 100644 --- a/test/jalview/ws/jabaws/DisorderAnnotExportImport.java +++ b/test/jalview/ws/jabaws/DisorderAnnotExportImport.java @@ -83,7 +83,11 @@ public class DisorderAnnotExportImport Thread.sleep(100); } SlivkaWSDiscoverer disc2 = SlivkaWSDiscoverer.getInstance(); - disc2.run(); + disc2.startDiscoverer(null); + while (disc2.isRunning()) + { + Thread.sleep(100); + } iupreds = new ArrayList<>(); for (ServiceWithParameters svc : disc2.getServices()) { -- 1.7.10.2