1f46fc3731511ecc084224f0d240a4a77204dca3
[jalview.git] / src / jalview / ws2 / client / slivka / SlivkaWSDiscoverer.java
1 package jalview.ws2.client.slivka;
2
3 import java.io.IOException;
4 import java.net.MalformedURLException;
5 import java.net.URISyntaxException;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.List;
9
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;
18
19 public class SlivkaWSDiscoverer extends AbstractWebServiceDiscoverer
20 {
21   private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS";
22
23   private static final URL DEFAULT_URL;
24   static
25   {
26     try
27     {
28       DEFAULT_URL = new URL("https://www.compbio.dundee.ac.uk/slivka/");
29     } catch (MalformedURLException e)
30     {
31       throw new AssertionError(e);
32     }
33   }
34
35   private static SlivkaWSDiscoverer instance = null;
36
37   private static ParamManager paramManager = null;
38
39   private SlivkaWSDiscoverer()
40   {
41   }
42
43   public static SlivkaWSDiscoverer getInstance()
44   {
45     if (instance == null)
46       instance = new SlivkaWSDiscoverer();
47     return instance;
48   }
49
50   public static void setParamManager(ParamManager manager)
51   {
52     paramManager = manager;
53   }
54
55   @Override
56   public int getStatusForUrl(URL url)
57   {
58     try
59     {
60       List<?> services = new SlivkaClient(url.toString()).getServices();
61       return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
62     } catch (IOException e)
63     {
64       Cache.log.error("slivka could not retrieve services from " + url, e);
65       return STATUS_INVALID;
66     }
67   }
68
69   @Override
70   protected String getUrlsPropertyKey()
71   {
72     return SLIVKA_HOST_URLS;
73   }
74
75   @Override
76   protected URL getDefaultUrl()
77   {
78     return DEFAULT_URL;
79   }
80
81   @Override
82   protected List<WebService<?>> fetchServices(URL url) throws IOException
83   {
84     ArrayList<WebService<?>> allServices = new ArrayList<>();
85     SlivkaClient slivkaClient;
86     try
87     {
88       slivkaClient = new SlivkaClient(url.toURI());
89     } catch (URISyntaxException e)
90     {
91       throw new MalformedURLException(e.getMessage());
92     }
93     for (var slivkaService : slivkaClient.getServices())
94     {
95       int serviceClass = getServiceClass(slivkaService);
96       if (serviceClass == SERVICE_CLASS_MSA)
97       {
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();
104
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);
110         if (canRealign)
111           actionBuilder.subcategory("Align");
112         actionBuilder.minSequences(2);
113         msaService.addAction(actionBuilder.build());
114         if (canRealign)
115         {
116           actionBuilder.name("Re-alignment");
117           actionBuilder.subcategory("Realign");
118           actionBuilder.submitGaps(true);
119           msaService.addAction(actionBuilder.build());
120         }
121         allServices.add(msaService);
122       }
123       else if (serviceClass == SERVICE_CLASS_PROT_SEQ_ANALYSIS)
124       {
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);
137       }
138       else if (serviceClass == SERVICE_CLASS_CONSERVATION)
139       {
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);
155       }
156       else if (serviceClass == SERVICE_CLASS_RNA_SEC_STR_PRED)
157       {
158
159       }
160       else
161       {
162         continue;
163       }
164     }
165     return allServices;
166   }
167
168   private void initServiceBuilder(SlivkaService service, WebService.Builder<?> wsBuilder)
169   {
170     try
171     {
172       wsBuilder.url(service.getUrl().toURL());
173     } catch (MalformedURLException e)
174     {
175       e.printStackTrace();
176     }
177     wsBuilder.clientName("slivka");
178     wsBuilder.name(service.getName());
179     wsBuilder.description(service.getDescription());
180     var storeBuilder = new SlivkaParamStoreFactory(service, paramManager);
181     wsBuilder.paramDatastore(storeBuilder.createParamDatastore());
182   }
183
184   static final int SERVICE_CLASS_UNSUPPORTED = -1;
185
186   static final int SERVICE_CLASS_MSA = 1;
187
188   static final int SERVICE_CLASS_RNA_SEC_STR_PRED = 2;
189
190   static final int SERVICE_CLASS_CONSERVATION = 3;
191
192   static final int SERVICE_CLASS_PROT_SEQ_ANALYSIS = 4;
193
194   static final int SERVICE_CLASS_PROT_SEC_STR_PRED = 5;
195
196   /**
197    * Scan service classifiers starting with operation :: analysis to decide the
198    * operation class.
199    * 
200    * @return service class flag
201    */
202   private static int getServiceClass(SlivkaService service)
203   {
204     for (String classifier : service.getClassifiers())
205     {
206       String[] path = classifier.split("\\s*::\\s*");
207       if (path.length < 3 || !path[0].equalsIgnoreCase("operation") ||
208           !path[1].equalsIgnoreCase("analysis"))
209         continue;
210       // classifier is operation :: analysis :: *
211       var tail = path[path.length - 1].toLowerCase();
212       switch (tail)
213       {
214       case "multiple sequence alignment":
215         return SERVICE_CLASS_MSA;
216       case "rna secondary structure prediction":
217         return SERVICE_CLASS_RNA_SEC_STR_PRED;
218       case "sequence alignment analysis (conservation)":
219         return SERVICE_CLASS_CONSERVATION;
220       case "protein sequence analysis":
221         return SERVICE_CLASS_PROT_SEQ_ANALYSIS;
222       case "protein secondary structure prediction":
223         return SERVICE_CLASS_PROT_SEC_STR_PRED;
224       }
225     }
226     return SERVICE_CLASS_UNSUPPORTED;
227   }
228 }