1 package jalview.ws2.client.slivka;
3 import java.io.IOException;
4 import java.net.MalformedURLException;
5 import java.net.URISyntaxException;
7 import java.util.ArrayList;
10 import jalview.bin.Cache;
11 import jalview.ws.params.ParamManager;
12 import jalview.ws2.actions.alignment.AlignmentAction;
13 import jalview.ws2.actions.annotation.AnnotationAction;
14 import jalview.ws2.api.WebService;
15 import jalview.ws2.client.api.AbstractWebServiceDiscoverer;
16 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
17 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
19 public class SlivkaWSDiscoverer extends AbstractWebServiceDiscoverer
21 private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS";
23 private static final URL DEFAULT_URL;
28 DEFAULT_URL = new URL("https://www.compbio.dundee.ac.uk/slivka/");
29 } catch (MalformedURLException e)
31 throw new AssertionError(e);
35 private static SlivkaWSDiscoverer instance = null;
37 private static ParamManager paramManager = null;
39 private SlivkaWSDiscoverer()
43 public static SlivkaWSDiscoverer getInstance()
46 instance = new SlivkaWSDiscoverer();
50 public static void setParamManager(ParamManager manager)
52 paramManager = manager;
56 public int getStatusForUrl(URL url)
60 List<?> services = new SlivkaClient(url.toString()).getServices();
61 return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
62 } catch (IOException e)
64 Cache.log.error("slivka could not retrieve services from " + url, e);
65 return STATUS_INVALID;
70 protected String getUrlsPropertyKey()
72 return SLIVKA_HOST_URLS;
76 protected URL getDefaultUrl()
82 protected List<WebService<?>> fetchServices(URL url) throws IOException
84 ArrayList<WebService<?>> allServices = new ArrayList<>();
85 SlivkaClient slivkaClient;
88 slivkaClient = new SlivkaClient(url.toURI());
89 } catch (URISyntaxException e)
91 throw new MalformedURLException(e.getMessage());
93 for (var slivkaService : slivkaClient.getServices())
95 int serviceClass = getServiceClass(slivkaService);
96 if (serviceClass == SERVICE_CLASS_MSA)
98 var wsb = WebService.<AlignmentAction> newBuilder();
99 initServiceBuilder(slivkaService, wsb);
100 wsb.category("Alignment");
101 wsb.interactive(false);
102 wsb.actionClass(AlignmentAction.class);
103 var msaService = wsb.build();
105 boolean canRealign = msaService.getName().contains("lustal");
106 var client = new SlivkaAlignmentWSClient(slivkaService);
107 var actionBuilder = AlignmentAction.newBuilder(client);
108 actionBuilder.name("Alignment");
109 actionBuilder.webService(msaService);
111 actionBuilder.subcategory("Align");
112 actionBuilder.minSequences(2);
113 msaService.addAction(actionBuilder.build());
116 actionBuilder.name("Re-alignment");
117 actionBuilder.subcategory("Realign");
118 actionBuilder.submitGaps(true);
119 msaService.addAction(actionBuilder.build());
121 allServices.add(msaService);
123 else if (serviceClass == SERVICE_CLASS_PROT_SEQ_ANALYSIS)
125 var wsb = WebService.<AnnotationAction> newBuilder();
126 initServiceBuilder(slivkaService, wsb);
127 wsb.category("Protein Disorder");
128 wsb.interactive(false);
129 wsb.actionClass(AnnotationAction.class);
130 var psaService = wsb.build();
131 var client = new SlivkaAnnotationWSClient(slivkaService);
132 var actionBuilder = AnnotationAction.newBuilder(client);
133 actionBuilder.webService(psaService);
134 actionBuilder.name("Analysis");
135 psaService.addAction(actionBuilder.build());
136 allServices.add(psaService);
138 else if (serviceClass == SERVICE_CLASS_CONSERVATION)
140 var wsb = WebService.<AnnotationAction> newBuilder();
141 initServiceBuilder(slivkaService, wsb);
142 wsb.category("Conservation");
143 wsb.interactive(true);
144 wsb.actionClass(AnnotationAction.class);
145 var conService = wsb.build();
146 var client = new SlivkaAnnotationWSClient(slivkaService);
147 var actionBuilder = AnnotationAction.newBuilder(client);
148 actionBuilder.webService(conService);
149 actionBuilder.name("");
150 actionBuilder.alignmentAnalysis(true);
151 actionBuilder.requireAlignedSequences(true);
152 actionBuilder.filterSymbols(true);
153 conService.addAction(actionBuilder.build());
154 allServices.add(conService);
156 else if (serviceClass == SERVICE_CLASS_RNA_SEC_STR_PRED)
158 var wsb = WebService.<AnnotationAction> newBuilder();
159 initServiceBuilder(slivkaService, wsb);
160 wsb.category("Secondary Structure Prediction");
161 wsb.interactive(true);
162 wsb.actionClass(AnnotationAction.class);
163 var predService = wsb.build();
164 var client = new SlivkaAnnotationWSClient(slivkaService);
165 var actionBuilder = AnnotationAction.newBuilder(client);
166 actionBuilder.webService(predService);
167 actionBuilder.name("Prediction");
168 actionBuilder.minSequences(2);
169 actionBuilder.allowNucleotide(true);
170 actionBuilder.allowProtein(false);
171 actionBuilder.alignmentAnalysis(true);
172 actionBuilder.requireAlignedSequences(true);
173 actionBuilder.filterSymbols(false);
174 predService.addAction(actionBuilder.build());
175 allServices.add(predService);
185 private void initServiceBuilder(SlivkaService service, WebService.Builder<?> wsBuilder)
189 wsBuilder.url(service.getClient().getUrl().toURL());
190 } catch (MalformedURLException e)
194 wsBuilder.clientName("slivka");
195 wsBuilder.name(service.getName());
196 wsBuilder.description(service.getDescription());
197 var storeBuilder = new SlivkaParamStoreFactory(service, paramManager);
198 wsBuilder.paramDatastore(storeBuilder.createParamDatastore());
201 static final int SERVICE_CLASS_UNSUPPORTED = -1;
203 static final int SERVICE_CLASS_MSA = 1;
205 static final int SERVICE_CLASS_RNA_SEC_STR_PRED = 2;
207 static final int SERVICE_CLASS_CONSERVATION = 3;
209 static final int SERVICE_CLASS_PROT_SEQ_ANALYSIS = 4;
211 static final int SERVICE_CLASS_PROT_SEC_STR_PRED = 5;
214 * Scan service classifiers starting with operation :: analysis to decide the
217 * @return service class flag
219 private static int getServiceClass(SlivkaService service)
221 for (String classifier : service.getClassifiers())
223 String[] path = classifier.split("\\s*::\\s*");
224 if (path.length < 3 || !path[0].equalsIgnoreCase("operation") ||
225 !path[1].equalsIgnoreCase("analysis"))
227 // classifier is operation :: analysis :: *
228 var tail = path[path.length - 1].toLowerCase();
231 case "multiple sequence alignment":
232 return SERVICE_CLASS_MSA;
233 case "rna secondary structure prediction":
234 return SERVICE_CLASS_RNA_SEC_STR_PRED;
235 case "sequence alignment analysis (conservation)":
236 return SERVICE_CLASS_CONSERVATION;
237 case "protein sequence analysis":
238 return SERVICE_CLASS_PROT_SEQ_ANALYSIS;
239 case "protein secondary structure prediction":
240 return SERVICE_CLASS_PROT_SEC_STR_PRED;
243 return SERVICE_CLASS_UNSUPPORTED;