fe5c040bb1b614754653126bf4121c307709cacd
[jalview.git] / src / jalview / ws2 / slivka / SlivkaWSDiscoverer.java
1 package jalview.ws2.slivka;
2
3 import java.io.IOException;
4 import java.net.MalformedURLException;
5 import java.net.URL;
6 import java.util.*;
7 import java.util.concurrent.*;
8
9 import jalview.bin.Cache;
10 import jalview.ws2.*;
11 import jalview.ws2.operations.AlignmentOperation;
12 import jalview.ws2.operations.Operation;
13 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
14 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
15
16 public class SlivkaWSDiscoverer implements WebServiceDiscoverer
17 {
18   private static final String SLIVKA_HOST_URLS = "SLIVKSHOSTURLS";
19
20   private static final String DEFAULT_URL = "https://www.compbio.dundee.ac.uk/slivka/";
21
22   private static SlivkaWSDiscoverer instance = null;
23
24   private List<WebServiceI> services = List.of();
25
26   private SlivkaWSDiscoverer()
27   {
28   }
29
30   public static SlivkaWSDiscoverer getInstance()
31   {
32     if (instance == null)
33     {
34       instance = new SlivkaWSDiscoverer();
35     }
36     return instance;
37   }
38
39   @Override
40   public List<String> getUrls() {
41     String surls = Cache.getDefault(SLIVKA_HOST_URLS, DEFAULT_URL);
42     String urls[] = surls.split(",");
43     ArrayList<String> valid = new ArrayList<>(urls.length);
44     for (String url : urls)
45     {
46       try
47       {
48         new URL(url);
49         valid.add(url);
50       }
51       catch (MalformedURLException e)
52       {
53         Cache.log.warn("Problem whilst trying to make a URL from '" +
54                 Objects.toString(url, "<null>") + "'. " +
55                 "This was probably due to malformed comma-separated-list " +
56                 "in the " + SLIVKA_HOST_URLS + " entry of ${HOME}/.jalview_properties");
57         Cache.log.debug("Exception occurred while reading url list", e);
58       }
59     }
60     return valid;
61   }
62
63   @Override
64   public void setUrls(List<String> wsUrls) {
65     if (wsUrls != null && !wsUrls.isEmpty())
66     {
67       Cache.setProperty(SLIVKA_HOST_URLS, String.join(",", wsUrls));
68     }
69     else {
70       Cache.removeProperty(SLIVKA_HOST_URLS);
71     }
72   }
73
74   @Override
75   public boolean testUrl(URL url) {
76     return getStatusForUrl(url.toString()) == STATUS_OK;
77   }
78
79   @Override
80   public int getStatusForUrl(String url) {
81     try
82     {
83       List<?> services = new SlivkaClient(url).getServices();
84       return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
85     }
86     catch (IOException e)
87     {
88       Cache.log.error("Slivka could not retrieve services list from " + url, e);
89       return STATUS_INVALID;
90     }
91   }
92
93   public List<WebServiceI> getServices() {
94     return Collections.unmodifiableList(services);
95   }
96
97   public boolean hasServices() {
98     return !isRunning() && services.size() > 0;
99   }
100
101   public boolean isRunning() {
102     for (Future<?> task : discoveryTasks) {
103       if (!task.isDone()) {
104         return false;
105       }
106     }
107     return true;
108   }
109
110   public boolean isDone() {
111     return !isRunning() && discoveryTasks.size() > 0;
112   }
113
114   private Vector<Future<?>> discoveryTasks = new Vector<>();
115
116   @Override
117   public CompletableFuture<WebServiceDiscoverer> startDiscoverer()
118   {
119     CompletableFuture<WebServiceDiscoverer> task = CompletableFuture
120             .supplyAsync(() -> {
121               reloadServices();
122               return SlivkaWSDiscoverer.this;
123             });
124     discoveryTasks.add(task);
125     return task;
126   }
127
128   private List<WebServiceI> reloadServices()
129   {
130     Cache.log.info("Reloading Slivka services");
131     fireServicesChanged(Collections.emptyList());
132     ArrayList<WebServiceI> allServices = new ArrayList<>();
133     for (String url : getUrls()) {
134       SlivkaClient client = new SlivkaClient(url);
135       List<SlivkaService> services;
136       try {
137         services = client.getServices();
138       } catch (IOException e) {
139         Cache.log.error("Unable to fetch services from " + url, e);
140         continue;
141       }
142       for (SlivkaService service : services) {
143         SlivkaWebService instance = new SlivkaWebService(client, service, service.getName());
144         for (String classifier : service.classifiers)
145         {
146           String[] path = classifier.split("\\s*::\\s*");
147           if (path.length >= 3 && path[0].toLowerCase().equals("operation")
148                   && path[1].toLowerCase().equals("analysis"))
149           {
150             Operation op = null;
151             switch (path[path.length - 1].toLowerCase()) {
152             case "multiple sequence alignment":
153               op = new AlignmentOperation(instance, instance::getAlignment);
154             }
155             if (op != null)
156               instance.addOperation(op);
157           }
158         }
159         if (instance.operations.size() > 0) {
160           allServices.add(instance);
161         }
162       }
163     }
164     this.services = allServices;
165     Cache.log.info("Reloading slivka services finished");
166     fireServicesChanged(getServices());
167     return allServices;
168   }
169
170   @Override
171   public String getErrorMessages() {
172     return "";
173   }
174
175 }