1 package jalview.ws.slivkaws;
3 import jalview.bin.Cache;
4 import jalview.bin.Console;
5 import jalview.ws.ServiceChangeListener;
6 import jalview.ws.WSDiscovererI;
7 import jalview.ws.api.ServiceWithParameters;
8 import javajs.http.HttpClientFactory;
10 import java.io.IOException;
11 import java.net.MalformedURLException;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
17 import java.util.Vector;
18 import java.util.concurrent.CompletableFuture;
19 import java.util.concurrent.CopyOnWriteArraySet;
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.Future;
24 import compbio.data.msa.Category;
25 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
26 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
28 public class SlivkaWSDiscoverer implements WSDiscovererI
30 private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS";
32 private static final String COMPBIO_SLIVKA = "https://www.compbio.dundee.ac.uk/slivka/";
34 private static SlivkaWSDiscoverer instance = null;
36 private List<ServiceWithParameters> services = List.of();
38 private SlivkaWSDiscoverer()
42 public static SlivkaWSDiscoverer getInstance()
46 instance = new SlivkaWSDiscoverer();
51 private Set<ServiceChangeListener> serviceListeners = new CopyOnWriteArraySet<>();
54 public void addServiceChangeListener(ServiceChangeListener l)
56 serviceListeners.add(l);
60 public void removeServiceChangeListener(ServiceChangeListener l)
62 serviceListeners.remove(l);
65 public void notifyServiceListeners(List<ServiceWithParameters> services)
67 for (var listener : serviceListeners)
69 listener.servicesChanged(this, services);
73 private final ExecutorService executor = Executors
74 .newSingleThreadExecutor();
76 private Vector<Future<?>> discoveryTasks = new Vector<>();
78 public CompletableFuture<WSDiscovererI> startDiscoverer()
80 CompletableFuture<WSDiscovererI> task = CompletableFuture
83 return SlivkaWSDiscoverer.this;
85 discoveryTasks.add(task);
89 private List<ServiceWithParameters> reloadServices()
91 Console.info("Reloading Slivka services");
92 notifyServiceListeners(Collections.emptyList());
93 ArrayList<ServiceWithParameters> instances = new ArrayList<>();
95 for (String url : getServiceUrls())
97 SlivkaClient client = new SlivkaClient(url);
99 List<SlivkaService> services;
102 services = client.getServices();
103 } catch (IOException e)
108 for (SlivkaService service : services)
110 SlivkaWSInstance newInstance = null;
111 for (String classifier : service.classifiers)
113 String[] path = classifier.split("\\s*::\\s*");
114 if (path.length >= 3 && path[0].toLowerCase().equals("operation")
115 && path[1].toLowerCase().equals("analysis"))
117 switch (path[path.length - 1].toLowerCase())
119 case "rna secondary structure prediction":
120 newInstance = new RNAalifoldServiceInstance(client,
121 service, "Secondary Structure Prediction");
123 case "sequence alignment analysis (conservation)":
124 newInstance = new SlivkaAnnotationServiceInstance(client,
125 service, Category.CATEGORY_CONSERVATION);
127 case "protein sequence analysis":
128 newInstance = new SlivkaAnnotationServiceInstance(client,
129 service, Category.CATEGORY_DISORDER);
131 case "protein secondary structure prediction":
132 newInstance = new SlivkaAnnotationServiceInstance(client,
133 service, "Secondary Structure Prediction");
135 case "multiple sequence alignment":
136 newInstance = new SlivkaMsaServiceInstance(client, service,
137 Category.CATEGORY_ALIGNMENT);
141 if (newInstance != null)
144 if (newInstance != null)
145 instances.add(newInstance);
149 services = instances;
150 Console.info("Slivka services reloading finished");
151 notifyServiceListeners(instances);
156 public List<ServiceWithParameters> getServices()
162 public boolean hasServices()
164 return !isRunning() && services.size() > 0;
168 public boolean isRunning()
170 return !discoveryTasks.stream().allMatch(Future::isDone);
174 public void setServiceUrls(List<String> wsUrls)
176 if (wsUrls != null && !wsUrls.isEmpty())
178 Cache.setProperty(SLIVKA_HOST_URLS, String.join(",", wsUrls));
182 Cache.removeProperty(SLIVKA_HOST_URLS);
187 public List<String> getServiceUrls()
189 String surls = Cache.getDefault(SLIVKA_HOST_URLS, COMPBIO_SLIVKA);
190 String[] urls = surls.split(",");
191 ArrayList<String> valid = new ArrayList<>(urls.length);
192 for (String url : urls)
198 } catch (MalformedURLException e)
200 Console.warn("Problem whilst trying to make a URL from '"
201 + ((url != null) ? url : "<null>") + "'");
203 "This was probably due to a malformed comma separated list"
204 + " in the " + SLIVKA_HOST_URLS
205 + " entry of $(HOME)/.jalview_properties)");
206 Console.debug("Exception was ", e);
213 public boolean testServiceUrl(URL url)
215 return getServerStatusFor(url.toString()) == STATUS_OK;
219 public int getServerStatusFor(String url)
223 List<?> services = new SlivkaClient(url).getServices();
224 return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
225 } catch (IOException | org.json.JSONException e)
227 Console.error("Slivka could not retrieve services list", e);
228 return STATUS_INVALID;
233 public String getErrorMessages()
235 // TODO Auto-generated method stub