1 package jalview.ws2.slivka;
3 import java.io.IOException;
4 import java.net.MalformedURLException;
7 import java.util.concurrent.*;
9 import jalview.bin.Cache;
10 import jalview.datamodel.AlignmentI;
11 import jalview.io.JPredFile;
13 import jalview.ws2.operations.*;
14 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
15 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
17 public class SlivkaWSDiscoverer implements WebServiceDiscovererI
19 private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS";
21 private static final String DEFAULT_URL = "https://www.compbio.dundee.ac.uk/slivka/";
23 private static SlivkaWSDiscoverer instance = null;
25 private List<Operation> operations = List.of();
27 private SlivkaWSDiscoverer()
31 public static SlivkaWSDiscoverer getInstance()
35 instance = new SlivkaWSDiscoverer();
41 public List<String> getUrls()
43 String surls = Cache.getDefault(SLIVKA_HOST_URLS, DEFAULT_URL);
44 String urls[] = surls.split(",");
45 ArrayList<String> valid = new ArrayList<>(urls.length);
46 for (String url : urls)
52 } catch (MalformedURLException e)
54 Cache.log.warn("Problem whilst trying to make a URL from '"
55 + Objects.toString(url, "<null>") + "'. "
56 + "This was probably due to malformed comma-separated-list "
57 + "in the " + SLIVKA_HOST_URLS
58 + " entry of ${HOME}/.jalview_properties");
59 Cache.log.debug("Exception occurred while reading url list", e);
66 public void setUrls(List<String> wsUrls)
68 if (wsUrls != null && !wsUrls.isEmpty())
70 Cache.setProperty(SLIVKA_HOST_URLS, String.join(",", wsUrls));
74 Cache.removeProperty(SLIVKA_HOST_URLS);
79 public boolean testUrl(URL url)
81 return getStatusForUrl(url.toString()) == STATUS_OK;
85 public int getStatusForUrl(String url)
89 List<?> services = new SlivkaClient(url).getServices();
90 return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
91 } catch (IOException e)
93 Cache.log.error("Slivka could not retrieve services list from " + url,
95 return STATUS_INVALID;
100 public List<Operation> getOperations()
102 return Collections.unmodifiableList(operations);
106 public boolean hasServices()
108 return !isRunning() && operations.size() > 0;
111 public boolean isRunning()
113 for (Future<?> task : discoveryTasks)
123 public boolean isDone()
125 return !isRunning() && discoveryTasks.size() > 0;
128 private Vector<Future<?>> discoveryTasks = new Vector<>();
131 public CompletableFuture<WebServiceDiscovererI> startDiscoverer()
133 CompletableFuture<WebServiceDiscovererI> task = CompletableFuture
136 return SlivkaWSDiscoverer.this;
138 task.thenRun(() -> fireOperationsChanged(getOperations()));
139 discoveryTasks.add(task);
143 private List<Operation> reloadServices()
145 Cache.log.info("Reloading Slivka services");
146 fireOperationsChanged(Collections.emptyList());
147 ArrayList<Operation> allOperations = new ArrayList<>();
148 for (String url : getUrls())
150 SlivkaClient client = new SlivkaClient(url);
151 List<SlivkaService> services;
154 services = client.getServices();
155 } catch (IOException e)
157 Cache.log.error("Unable to fetch services from " + url, e);
160 for (SlivkaService service : services)
162 final SlivkaWebService webService = new SlivkaWebService(client, service);
163 AbstractOperation op = null;
164 for (String classifier : service.classifiers)
166 String[] path = classifier.split("\\s*::\\s*");
167 if (path.length >= 3 && path[0].toLowerCase().equals("operation")
168 && path[1].toLowerCase().equals("analysis"))
170 switch (path[path.length - 1].toLowerCase())
172 case "rna secondary structure prediction":
173 op = new AnnotationOperation(webService,
174 "Secondary Structure Prediction", webService::attachAnnotations);
175 op.setInteractive(true);
176 op.setAlignmentAnalysis(true);
177 op.setProteinOperation(false);
179 case "sequence alignment analysis (conservation)":
180 op = new AnnotationOperation(webService, "Conservation",
181 webService::attachAnnotations);
182 op.setAlignmentAnalysis(true);
183 op.setInteractive(true);
185 case "protein sequence analysis":
186 op = new AnnotationOperation(webService, "Protein Disorder",
187 webService::attachAnnotations);
189 case "protein secondary structure prediction":
190 var predictionSupplier = new JPredOperation.PredictionResultSupplier()
193 public JPredFile getPrediction(WSJob job) throws IOException
195 return webService.getPrediction(job);
199 public AlignmentI getAlignment(WSJob job) throws IOException
201 return webService.getAlignment(job);
204 op = new JPredOperation(webService,
205 "Secondary Structure Prediction", predictionSupplier);
207 case "multiple sequence alignment":
208 op = new AlignmentOperation(webService, webService::getAlignment);
219 allOperations.add(op);
223 this.operations = allOperations;
224 Cache.log.info("Reloading slivka services finished");
225 return allOperations;
229 public String getErrorMessages()
235 private OperationsChangeListenerList operationsChangeListeners =
236 new OperationsChangeListenerList(this);
239 public void addOperationsChangeListener(OperationsChangeListener listener)
241 operationsChangeListeners.addListener(listener);
245 public void removeOperationsChangeListener(
246 OperationsChangeListener listener)
248 operationsChangeListeners.removeListener(listener);
251 private void fireOperationsChanged(List<Operation> list)
253 operationsChangeListeners.fireOperationsChanged(list);