a5f51ab19c49e164d95e3e9176b80987d72a3823
[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.api.WebService;
14 import jalview.ws2.client.api.AbstractWebServiceDiscoverer;
15 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
16 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
17
18 public class SlivkaWSDiscoverer extends AbstractWebServiceDiscoverer
19 {
20   private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS";
21
22   private static final URL DEFAULT_URL;
23   static
24   {
25     try
26     {
27       DEFAULT_URL = new URL("https://www.compbio.dundee.ac.uk/slivka/");
28     } catch (MalformedURLException e)
29     {
30       throw new AssertionError(e);
31     }
32   }
33
34   private static SlivkaWSDiscoverer instance = null;
35
36   private static ParamManager paramManager = null;
37
38   private SlivkaWSDiscoverer()
39   {
40   }
41
42   public static SlivkaWSDiscoverer getInstance()
43   {
44     if (instance == null)
45       instance = new SlivkaWSDiscoverer();
46     return instance;
47   }
48
49   public static void setParamManager(ParamManager manager)
50   {
51     paramManager = manager;
52   }
53
54   @Override
55   public int getStatusForUrl(URL url)
56   {
57     try
58     {
59       List<?> services = new SlivkaClient(url.toString()).getServices();
60       return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
61     } catch (IOException e)
62     {
63       Cache.log.error("slivka could not retrieve services from " + url, e);
64       return STATUS_INVALID;
65     }
66   }
67
68   @Override
69   protected String getUrlsPropertyKey()
70   {
71     return SLIVKA_HOST_URLS;
72   }
73
74   @Override
75   protected URL getDefaultUrl()
76   {
77     return DEFAULT_URL;
78   }
79
80   @Override
81   protected List<WebService<?>> fetchServices(URL url) throws IOException
82   {
83     ArrayList<WebService<?>> allServices = new ArrayList<>();
84     SlivkaClient slivkaClient;
85     try
86     {
87       slivkaClient = new SlivkaClient(url.toURI());
88     } catch (URISyntaxException e)
89     {
90       throw new MalformedURLException(e.getMessage());
91     }
92     for (var slivkaService : slivkaClient.getServices())
93     {
94       int serviceClass = getServiceClass(slivkaService);
95       if (serviceClass == SERVICE_CLASS_MSA)
96       {
97         var wsb = WebService.<AlignmentAction> newBuilder();
98         initServiceBuilder(slivkaService, wsb);
99         wsb.category("Alignment");
100         wsb.interactive(false);
101         wsb.actionClass(AlignmentAction.class);
102         var msaService = wsb.build();
103
104         boolean canRealign = msaService.getName().endsWith("lustal");
105         var client = new SlivkaAlignmentWSClient(slivkaService);
106         var actionBuilder = AlignmentAction.newBuilder(client);
107         actionBuilder.name("Alignment");
108         actionBuilder.webService(msaService);
109         if (canRealign)
110           actionBuilder.subcategory("Align");
111         actionBuilder.minSequences(2);
112         msaService.addAction(actionBuilder.build());
113         if (canRealign)
114         {
115           actionBuilder.name("Re-alignment");
116           actionBuilder.subcategory("Realign");
117           actionBuilder.submitGaps(true);
118           msaService.addAction(actionBuilder.build());
119         }
120         allServices.add(msaService);
121       }
122       else
123       {
124         continue;
125       }
126     }
127     return allServices;
128   }
129
130   private void initServiceBuilder(SlivkaService service, WebService.Builder<?> wsBuilder)
131   {
132     try
133     {
134       wsBuilder.url(service.getUrl().toURL());
135     } catch (MalformedURLException e)
136     {
137       e.printStackTrace();
138     }
139     wsBuilder.clientName("slivka");
140     wsBuilder.name(service.getName());
141     wsBuilder.description(service.getDescription());
142     var storeBuilder = new SlivkaParamStoreFactory(service, paramManager);
143     wsBuilder.paramDatastore(storeBuilder.createParamDatastore());
144   }
145
146   static final int SERVICE_CLASS_UNSUPPORTED = -1;
147
148   static final int SERVICE_CLASS_MSA = 1;
149
150   static final int SERVICE_CLASS_RNA_SEC_STR_PRED = 2;
151
152   static final int SERVICE_CLASS_CONSERVATION = 3;
153
154   static final int SERVICE_CLASS_PROT_SEQ_ANALYSIS = 4;
155
156   static final int SERVICE_CLASS_PROT_SEC_STR_PRED = 5;
157
158   /**
159    * Scan service classifiers starting with operation :: analysis to decide the
160    * operation class.
161    * 
162    * @return service class flag
163    */
164   private static int getServiceClass(SlivkaService service)
165   {
166     for (String classifier : service.getClassifiers())
167     {
168       String[] path = classifier.split("\\s*::\\s*");
169       if (path.length < 3 || !path[0].equalsIgnoreCase("operation") ||
170           !path[1].equalsIgnoreCase("analysis"))
171         continue;
172       // classifier is operation :: analysis :: *
173       var tail = path[path.length - 1].toLowerCase();
174       switch (tail)
175       {
176       case "multiple sequence alignment":
177         return SERVICE_CLASS_MSA;
178       case "rna secondary structure prediction":
179         return SERVICE_CLASS_RNA_SEC_STR_PRED;
180       case "sequence alignment analysis (conservation)":
181         return SERVICE_CLASS_CONSERVATION;
182       case "protein sequence analysis":
183         return SERVICE_CLASS_PROT_SEQ_ANALYSIS;
184       case "protein secondary structure prediction":
185         return SERVICE_CLASS_PROT_SEC_STR_PRED;
186       }
187     }
188     return SERVICE_CLASS_UNSUPPORTED;
189   }
190 }