1 package jalview.ws2.client.slivka;
3 import java.io.IOException;
4 import java.net.MalformedURLException;
6 import java.net.URISyntaxException;
8 import java.util.ArrayList;
10 import java.util.function.Function;
12 import jalview.bin.Cache;
13 import jalview.bin.Console;
14 import jalview.ws.params.ParamManager;
15 import jalview.ws2.actions.alignment.AlignmentAction;
16 import jalview.ws2.actions.annotation.AnnotationAction;
17 import jalview.ws2.api.WebService;
18 import jalview.ws2.client.api.AbstractWebServiceDiscoverer;
19 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
20 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
22 public class SlivkaWSDiscoverer extends AbstractWebServiceDiscoverer
24 private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS";
26 private static final URL DEFAULT_URL;
31 DEFAULT_URL = new URL("https://www.compbio.dundee.ac.uk/slivka/");
32 } catch (MalformedURLException e)
34 throw new AssertionError(e);
38 private static SlivkaWSDiscoverer instance = null;
40 private static ParamManager paramManager = null;
42 private final Function<URI, SlivkaClient> clientFactory;
44 SlivkaWSDiscoverer(Function<URI, SlivkaClient> clientFactory)
46 this.clientFactory = clientFactory;
49 public static SlivkaWSDiscoverer getInstance()
52 instance = new SlivkaWSDiscoverer(SlivkaClient::newInstance);
56 public static void setParamManager(ParamManager manager)
58 paramManager = manager;
62 public int getStatusForUrl(URL url)
66 List<?> services = clientFactory.apply(url.toURI()).getServices();
67 return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
68 } catch (URISyntaxException e)
70 Console.error("invalid URL " + url, e);
71 return STATUS_INVALID;
72 } catch (IOException e)
74 Console.error("slivka could not retrieve services from " + url, e);
75 return STATUS_INVALID;
80 protected String getUrlsPropertyKey()
82 return SLIVKA_HOST_URLS;
86 protected URL getDefaultUrl()
92 protected List<WebService<?>> fetchServices(URL url) throws IOException
94 ArrayList<WebService<?>> allServices = new ArrayList<>();
95 SlivkaClient slivkaClient;
98 slivkaClient = clientFactory.apply(url.toURI());
99 } catch (URISyntaxException e)
101 throw new MalformedURLException(e.getMessage());
103 for (var slivkaService : slivkaClient.getServices())
105 int serviceClass = getServiceClass(slivkaService);
106 if (serviceClass == SERVICE_CLASS_MSA)
108 var wsb = WebService.<AlignmentAction> newBuilder();
109 initServiceBuilder(slivkaClient, slivkaService, wsb);
110 wsb.category("Alignment");
111 wsb.interactive(false);
112 wsb.actionClass(AlignmentAction.class);
113 var msaService = wsb.build();
115 boolean canRealign = msaService.getName().contains("lustal");
116 var client = new SlivkaAlignmentWSClient(slivkaClient, slivkaService);
117 var actionBuilder = AlignmentAction.newBuilder(client);
118 actionBuilder.name("Alignment");
119 actionBuilder.webService(msaService);
121 actionBuilder.subcategory("Align");
122 actionBuilder.minSequences(2);
123 msaService.addAction(actionBuilder.build());
126 actionBuilder.name("Re-alignment");
127 actionBuilder.subcategory("Realign");
128 actionBuilder.submitGaps(true);
129 msaService.addAction(actionBuilder.build());
131 allServices.add(msaService);
133 else if (serviceClass == SERVICE_CLASS_PROT_SEQ_ANALYSIS)
135 var wsb = WebService.<AnnotationAction> newBuilder();
136 initServiceBuilder(slivkaClient, slivkaService, wsb);
137 wsb.category("Protein Disorder");
138 wsb.interactive(false);
139 wsb.actionClass(AnnotationAction.class);
140 var psaService = wsb.build();
141 var client = new SlivkaAnnotationWSClient(slivkaClient, slivkaService);
142 var actionBuilder = AnnotationAction.newBuilder(client);
143 actionBuilder.webService(psaService);
144 actionBuilder.name("Analysis");
145 psaService.addAction(actionBuilder.build());
146 allServices.add(psaService);
148 else if (serviceClass == SERVICE_CLASS_CONSERVATION)
150 var wsb = WebService.<AnnotationAction> newBuilder();
151 initServiceBuilder(slivkaClient, slivkaService, wsb);
152 wsb.category("Conservation");
153 wsb.interactive(true);
154 wsb.actionClass(AnnotationAction.class);
155 var conService = wsb.build();
156 var client = new SlivkaAnnotationWSClient(slivkaClient, slivkaService);
157 var actionBuilder = AnnotationAction.newBuilder(client);
158 actionBuilder.webService(conService);
159 actionBuilder.name("");
160 actionBuilder.alignmentAnalysis(true);
161 actionBuilder.requireAlignedSequences(true);
162 actionBuilder.filterSymbols(true);
163 conService.addAction(actionBuilder.build());
164 allServices.add(conService);
166 else if (serviceClass == SERVICE_CLASS_RNA_SEC_STR_PRED)
168 var wsb = WebService.<AnnotationAction> newBuilder();
169 initServiceBuilder(slivkaClient, slivkaService, wsb);
170 wsb.category("Secondary Structure Prediction");
171 wsb.interactive(true);
172 wsb.actionClass(AnnotationAction.class);
173 var predService = wsb.build();
174 var client = new SlivkaAnnotationWSClient(slivkaClient, slivkaService);
175 var actionBuilder = AnnotationAction.newBuilder(client);
176 actionBuilder.webService(predService);
177 actionBuilder.name("Prediction");
178 actionBuilder.minSequences(2);
179 actionBuilder.allowNucleotide(true);
180 actionBuilder.allowProtein(false);
181 actionBuilder.alignmentAnalysis(true);
182 actionBuilder.requireAlignedSequences(true);
183 actionBuilder.filterSymbols(false);
184 predService.addAction(actionBuilder.build());
185 allServices.add(predService);
195 private void initServiceBuilder(SlivkaClient client, SlivkaService service, WebService.Builder<?> wsBuilder)
199 wsBuilder.url(client.getUrl().toURL());
200 } catch (MalformedURLException e)
204 wsBuilder.clientName("slivka");
205 wsBuilder.name(service.getName());
206 wsBuilder.description(service.getDescription());
207 var storeBuilder = new SlivkaParamStoreFactory(service, paramManager);
208 wsBuilder.paramDatastore(storeBuilder.createParamDatastore());
211 static final int SERVICE_CLASS_UNSUPPORTED = -1;
213 static final int SERVICE_CLASS_MSA = 1;
215 static final int SERVICE_CLASS_RNA_SEC_STR_PRED = 2;
217 static final int SERVICE_CLASS_CONSERVATION = 3;
219 static final int SERVICE_CLASS_PROT_SEQ_ANALYSIS = 4;
221 static final int SERVICE_CLASS_PROT_SEC_STR_PRED = 5;
224 * Scan service classifiers starting with operation :: analysis to decide the
227 * @return service class flag
229 private static int getServiceClass(SlivkaService service)
231 for (String classifier : service.getClassifiers())
233 String[] path = classifier.split("\\s*::\\s*");
234 if (path.length < 3 || !path[0].equalsIgnoreCase("operation"))
236 // classifier is operation :: *
237 var tail = path[path.length - 1].toLowerCase();
240 case "multiple sequence alignment":
241 return SERVICE_CLASS_MSA;
242 case "rna secondary structure prediction":
243 return SERVICE_CLASS_RNA_SEC_STR_PRED;
244 case "sequence alignment analysis (conservation)":
245 return SERVICE_CLASS_CONSERVATION;
246 case "protein sequence analysis":
247 return SERVICE_CLASS_PROT_SEQ_ANALYSIS;
248 case "protein secondary structure prediction":
249 return SERVICE_CLASS_PROT_SEC_STR_PRED;
252 return SERVICE_CLASS_UNSUPPORTED;