package jalview.ws.slivkaws;
import jalview.bin.Cache;
-import jalview.gui.AlignFrame;
+import jalview.ws.ServiceChangeListener;
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.IOException;
import java.net.MalformedURLException;
-import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
-
-import javax.swing.JMenu;
-
+import java.util.Set;
+import java.util.Vector;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
{
private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS";
- private static final String COMPBIO_SLIVKA = "https://www.compbio.dundee.ac.uk/slivka";
+ private static final String COMPBIO_SLIVKA = "https://www.compbio.dundee.ac.uk/slivka/";
private static SlivkaWSDiscoverer instance = null;
return instance;
}
- private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
- this);
+ private Set<ServiceChangeListener> serviceListeners = new CopyOnWriteArraySet<>();
@Override
- public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame)
+ public void addServiceChangeListener(ServiceChangeListener l)
{
- 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);
-
+ serviceListeners.add(l);
}
- volatile boolean ready = false;
-
- volatile Thread discovererThread = null;
-
- private class DiscovererThread extends Thread
+ @Override
+ public void removeServiceChangeListener(ServiceChangeListener l)
{
- private Thread oldThread;
-
- DiscovererThread(Thread oldThread)
- {
- super();
- this.oldThread = oldThread;
- }
+ serviceListeners.remove(l);
+ }
- @Override
- public void run()
+ public void notifyServiceListeners(List<ServiceWithParameters> services)
+ {
+ for (var listener : serviceListeners)
{
- if (oldThread != null)
- {
- oldThread.interrupt();
- try
- {
- oldThread.join();
- } catch (InterruptedException e)
- {
- return;
- } finally
- {
- oldThread = null;
- }
- }
- ready = false;
- reloadServices();
- ready = !isInterrupted();
+ listener.servicesChanged(this, services);
}
}
- Thread discoverer = null;
+ private final ExecutorService executor = Executors.newSingleThreadExecutor();
+ private Vector<Future<?>> discoveryTasks = new Vector<>();
- @Override
- public Thread startDiscoverer(PropertyChangeListener changeListener)
+ public CompletableFuture<WSDiscovererI> startDiscoverer()
{
- changeSupport.addPropertyChangeListener(changeListener);
- ready = false;
- (discovererThread = new DiscovererThread(discovererThread)).start();
- return discovererThread;
+ CompletableFuture<WSDiscovererI> task = CompletableFuture
+ .supplyAsync(() -> {
+ reloadServices();
+ return SlivkaWSDiscoverer.this;
+ }, executor);
+ discoveryTasks.add(task);
+ return task;
}
- private void reloadServices()
+ private List<ServiceWithParameters> reloadServices()
{
Cache.log.info("Reloading Slivka services");
- changeSupport.firePropertyChange("services", services, List.of());
+ notifyServiceListeners(Collections.emptyList());
ArrayList<ServiceWithParameters> instances = new ArrayList<>();
for (String url : getServiceUrls())
{
Cache.log.info(url);
SlivkaClient client;
- try
- {
- client = new SlivkaClient(url);
- } catch (URISyntaxException e)
- {
- e.printStackTrace();
- continue;
- }
+ client = new SlivkaClient(url);
try
{
for (SlivkaService service : client.getServices())
}
} catch (IOException e)
{
+ e.printStackTrace();
continue;
}
}
services = instances;
- changeSupport.firePropertyChange("services", List.of(), services);
-
+ notifyServiceListeners(instances);
Cache.log.info("Slivka services reloading finished");
+ return instances;
}
@Override
@Override
public boolean hasServices()
{
- return ready == true && services.size() > 0;
+ return !isRunning() && services.size() > 0;
}
@Override
public boolean isRunning()
{
- return discovererThread == null || discovererThread.isAlive()
- || discovererThread.getState() == Thread.State.NEW;
+ return !discoveryTasks.stream().allMatch(Future::isDone);
}
@Override
{
List<?> services = new SlivkaClient(url).getServices();
return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
- } catch (IOException | URISyntaxException e)
+ } catch (IOException e)
{
+ Cache.log.error("Slivka could not retrieve services list", e);
return STATUS_INVALID;
}
}