JAL-3878 Code reformatting.
[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   {
42     String surls = Cache.getDefault(SLIVKA_HOST_URLS, DEFAULT_URL);
43     String urls[] = surls.split(",");
44     ArrayList<String> valid = new ArrayList<>(urls.length);
45     for (String url : urls)
46     {
47       try
48       {
49         new URL(url);
50         valid.add(url);
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
57                 + " entry of ${HOME}/.jalview_properties");
58         Cache.log.debug("Exception occurred while reading url list", e);
59       }
60     }
61     return valid;
62   }
63
64   @Override
65   public void setUrls(List<String> wsUrls)
66   {
67     if (wsUrls != null && !wsUrls.isEmpty())
68     {
69       Cache.setProperty(SLIVKA_HOST_URLS, String.join(",", wsUrls));
70     }
71     else
72     {
73       Cache.removeProperty(SLIVKA_HOST_URLS);
74     }
75   }
76
77   @Override
78   public boolean testUrl(URL url)
79   {
80     return getStatusForUrl(url.toString()) == STATUS_OK;
81   }
82
83   @Override
84   public int getStatusForUrl(String url)
85   {
86     try
87     {
88       List<?> services = new SlivkaClient(url).getServices();
89       return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
90     } catch (IOException e)
91     {
92       Cache.log.error("Slivka could not retrieve services list from " + url,
93               e);
94       return STATUS_INVALID;
95     }
96   }
97
98   public List<WebServiceI> getServices()
99   {
100     return Collections.unmodifiableList(services);
101   }
102
103   public boolean hasServices()
104   {
105     return !isRunning() && services.size() > 0;
106   }
107
108   public boolean isRunning()
109   {
110     for (Future<?> task : discoveryTasks)
111     {
112       if (!task.isDone())
113       {
114         return false;
115       }
116     }
117     return true;
118   }
119
120   public boolean isDone()
121   {
122     return !isRunning() && discoveryTasks.size() > 0;
123   }
124
125   private Vector<Future<?>> discoveryTasks = new Vector<>();
126
127   @Override
128   public CompletableFuture<WebServiceDiscoverer> startDiscoverer()
129   {
130     CompletableFuture<WebServiceDiscoverer> task = CompletableFuture
131             .supplyAsync(() -> {
132               reloadServices();
133               return SlivkaWSDiscoverer.this;
134             });
135     discoveryTasks.add(task);
136     return task;
137   }
138
139   private List<WebServiceI> reloadServices()
140   {
141     Cache.log.info("Reloading Slivka services");
142     fireServicesChanged(Collections.emptyList());
143     ArrayList<WebServiceI> allServices = new ArrayList<>();
144     for (String url : getUrls())
145     {
146       SlivkaClient client = new SlivkaClient(url);
147       List<SlivkaService> services;
148       try
149       {
150         services = client.getServices();
151       } catch (IOException e)
152       {
153         Cache.log.error("Unable to fetch services from " + url, e);
154         continue;
155       }
156       for (SlivkaService service : services)
157       {
158         SlivkaWebService instance = new SlivkaWebService(client, service,
159                 service.getName());
160         for (String classifier : service.classifiers)
161         {
162           String[] path = classifier.split("\\s*::\\s*");
163           if (path.length >= 3 && path[0].toLowerCase().equals("operation")
164                   && path[1].toLowerCase().equals("analysis"))
165           {
166             Operation op = null;
167             switch (path[path.length - 1].toLowerCase())
168             {
169             case "multiple sequence alignment":
170               op = new AlignmentOperation(instance, instance::getAlignment);
171             }
172             if (op != null)
173               instance.addOperation(op);
174           }
175         }
176         if (instance.operations.size() > 0)
177         {
178           allServices.add(instance);
179         }
180       }
181     }
182     this.services = allServices;
183     Cache.log.info("Reloading slivka services finished");
184     fireServicesChanged(getServices());
185     return allServices;
186   }
187
188   @Override
189   public String getErrorMessages()
190   {
191     return "";
192   }
193
194 }