Define proper test for JpredWS
[jabaws.git] / webservices / compbio / ws / client / WSTester.java
1 /* Copyright (c) 2011 Peter Troshin\r
2  * Copyright (c) 2013 Alexander Sherstnev\r
3  *  \r
4  *  JAva Bioinformatics Analysis Web Services (JABAWS) @version: 2.0\r
5  * \r
6  *  This library is free software; you can redistribute it and/or modify it under the terms of the\r
7  *  Apache License version 2 as published by the Apache Software Foundation\r
8  * \r
9  *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without\r
10  *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache \r
11  *  License for more details.\r
12  * \r
13  *  A copy of the license is in apache_license.txt. It is also available here:\r
14  * @see: http://www.apache.org/licenses/LICENSE-2.0.txt\r
15  * \r
16  * Any republication or derived work distributed in source code form\r
17  * must include this copyright and license notice.\r
18  */\r
19 \r
20 package compbio.ws.client;\r
21 \r
22 import static compbio.ws.client.Constraints.hostkey;\r
23 import static compbio.ws.client.Constraints.pseparator;\r
24 import static compbio.ws.client.Constraints.servicekey;\r
25 \r
26 import java.io.ByteArrayInputStream;\r
27 import java.io.Closeable;\r
28 import java.io.IOException;\r
29 import java.io.PrintWriter;\r
30 import java.net.ConnectException;\r
31 import java.util.Arrays;\r
32 import java.util.List;\r
33 \r
34 import javax.xml.ws.WebServiceException;\r
35 \r
36 import compbio.data.msa.JABAService;\r
37 import compbio.data.msa.Metadata;\r
38 import compbio.data.msa.MsaWS;\r
39 import compbio.data.msa.SequenceAnnotation;\r
40 import compbio.data.sequence.Alignment;\r
41 import compbio.data.sequence.FastaSequence;\r
42 import compbio.data.sequence.ScoreManager;\r
43 import compbio.data.sequence.SequenceUtil;\r
44 import compbio.metadata.JobStatus;\r
45 import compbio.metadata.Limit;\r
46 import compbio.metadata.LimitsManager;\r
47 import compbio.metadata.Option;\r
48 import compbio.metadata.Preset;\r
49 import compbio.metadata.PresetManager;\r
50 import compbio.metadata.RunnerConfig;\r
51 import compbio.metadata.UnsupportedRuntimeException;\r
52 import compbio.util.FileUtil;\r
53 import compbio.util.Util;\r
54 \r
55 /**\r
56  * Class for testing web services\r
57  * \r
58  * @author pvtroshin\r
59  * \r
60  * @version 1.5 February 2013\r
61  */\r
62 public class WSTester {\r
63 \r
64         /**\r
65          * Test sequences to be used as input for WS\r
66          */\r
67         public static final String fastaInput2records = \r
68                         ">Foo\nMTADGPRELLQLRAAVRHRPQDFVAWLMLADAELGMGDTTAGEMAVQRGLALHPGHPEAV\n"\r
69                 +   ">Bar\nASDAAPEHPGIALWLHALEDAGQAEAAAAYTRAHQLLPEEPYITAQLLNAVA\n";\r
70         public static final String fastaInput1record = \r
71                         ">Foo\nMTADGPRELLQLRAAVRHRPQDFVAWLMLADAELGMGDTTAGEMAVQRGLALHPGHPEAV\n";\r
72         public static final String fastaAlignment = \r
73                         ">Foo\nMTADGPRELLQLRAAVRHRPQDFVAWLMLADAELGMGDTTAGEMAVQRGLALHPGHPEAV--------\n"\r
74                 +   ">Bar\nASDAAPEH------------PGIALWLHALE-DAGQAEAAA---AYTRAHQLLPEEPYITAQLLNAVA\n";\r
75         public static final String fastaRNAAlignment = \r
76                         ">Foo\nC-UUGCGUUAAUGAGAACAGAAACG-UAAA--CUAUAA-CCUAG-G-GGUUUCUGUUGGAUGGUUG----GCAAC\n"\r
77                 +   ">Bar\nG-UGGCGCUUAUGACGCAGUUGUCU-UAAA-CUCGAAC--UCGA-GCGGGCAAUUGCUGAU-UACGAUUAACCAC\n";\r
78 \r
79         /**\r
80          * Status strings\r
81          */\r
82         private static final String FAILED = "FAILED";\r
83         private static final String OK = "OK";\r
84         private static final String UNSUPPORTED = "UNSUPPORTED";\r
85 \r
86         /**\r
87          * Converting input to a form accepted by WS\r
88          * \r
89          * @return List of FastaSequence records\r
90          */\r
91         private static List<FastaSequence> loadSeqs(int nLines) {\r
92                 try {\r
93                         if (nLines == 1) {\r
94                                 return SequenceUtil.readFasta(new ByteArrayInputStream(fastaInput1record.getBytes()));\r
95                         }\r
96                         return SequenceUtil.readFasta(new ByteArrayInputStream(fastaInput2records.getBytes()));\r
97                 } catch (IOException ignored) {\r
98                         // Should not happen as a source is not a external stream\r
99                         ignored.printStackTrace();\r
100                 }\r
101                 return null;\r
102         }\r
103 \r
104         /**\r
105          * Converting input to a form accepted by WS\r
106          * \r
107          * @return List of FastaSequence records\r
108          */\r
109         private static List<FastaSequence> loadAlignment() {\r
110                 try {\r
111                         return SequenceUtil.readFasta(new ByteArrayInputStream(\r
112                                         fastaAlignment.getBytes()));\r
113                 } catch (IOException ignored) {\r
114                         // Should not happen as a source is not a external stream\r
115                         ignored.printStackTrace();\r
116                 }\r
117                 return null;\r
118         }\r
119         /**\r
120          * Converting input to a form accepted by WS\r
121          * \r
122          * @return List of FastaSequence records with aligned RNA sequences\r
123          */\r
124         private static List<FastaSequence> loadRNAAlignment() {\r
125                 try {\r
126                         return SequenceUtil.readFasta(new ByteArrayInputStream(fastaRNAAlignment.getBytes()));\r
127                 } catch (IOException ignored) {\r
128                         // Should not happen as a source is not a external stream\r
129                         ignored.printStackTrace();\r
130                 }\r
131                 return null;\r
132         }\r
133 \r
134         private final PrintWriter writer;\r
135         private final String hostname;\r
136 \r
137         /**\r
138          * Construct an instance of JABAWS tester\r
139          * \r
140          * @param hostname\r
141          *            - fully qualified host and context name of JABAWS e.g.\r
142          *            http://nanna.cluster.lifesci.dundee.ac.uk:8080/jaba\r
143          * @param writer\r
144          *            a PrintWriter instance to writer test log to.\r
145          */\r
146         public WSTester(String hostname, PrintWriter writer) {\r
147                 if (Util.isEmpty(hostname)) {\r
148                         throw new NullPointerException("Hostname must be provided!");\r
149                 }\r
150                 this.hostname = hostname;\r
151                 this.writer = writer;\r
152         }\r
153 \r
154         /**\r
155          * Prints usage\r
156          */\r
157         static void printUsage() {\r
158                 System.out.println("Usage: <Class or Jar file name> " + hostkey\r
159                                 + pseparator + "host_and_context " + "<" + servicekey\r
160                                 + pseparator + "serviceName>");\r
161                 System.out.println();\r
162                 System.out.println(hostkey\r
163                                                 + pseparator\r
164                                                 + "<host_and_context> - a full URL to the JABAWS web server including context path e.g. http://10.31.1.159:8080/ws");\r
165                 System.out.println(servicekey\r
166                                                 + pseparator\r
167                                                 + "<ServiceName> - optional if unspecified all services are tested otherwise one of "\r
168                                                 + Arrays.toString(Services.values()));\r
169                 System.out.println();\r
170 \r
171         }\r
172 \r
173         /**\r
174          * Calls alignment with preset\r
175          * \r
176          * @param <T>\r
177          * @param msaws\r
178          * @param presets\r
179          *            list of the Preset\r
180          * @throws UnsupportedRuntimeException\r
181          */\r
182         private <T> boolean presetAlign(MsaWS<T> msaws, List<Preset<T>> presets)\r
183                         throws UnsupportedRuntimeException {\r
184                 boolean succeed = false;\r
185                 for (Preset<T> preset : presets) {\r
186                         writer.print("Aligning with preset '" + preset.getName() + "'... ");\r
187                         Alignment al = null;\r
188                         try {\r
189                                 String taskId = msaws.presetAlign(loadSeqs(2), preset);\r
190                                 al = msaws.getResult(taskId);\r
191                                 if (al != null) {\r
192                                         writer.println(OK);\r
193                                 }\r
194                                 succeed = true;\r
195                         } catch (Exception e) {\r
196                                 if (e instanceof UnsupportedRuntimeException) {\r
197                                         // If executable is not supported than none of the presets\r
198                                         // are\r
199                                         // going to work\r
200                                         throw (UnsupportedRuntimeException) e;\r
201                                 } else {\r
202                                         reportException(e);\r
203                                 }\r
204                                 continue;\r
205                         }\r
206                 }\r
207                 return succeed;\r
208         }\r
209 \r
210         private <T> boolean testMsaWS(MsaWS<T> msaws, Services service) throws Exception {\r
211                 assert msaws != null;\r
212 \r
213                 boolean succeed = testDefaultAlignment(msaws, service);\r
214                 // If exception above is thrown than the tests below is not run\r
215 \r
216                 PresetManager<T> pmanager = msaws.getPresets();\r
217                 if (pmanager != null && pmanager.getPresets().size() > 0) {\r
218                         writer.println("Testing alignment with presets:");\r
219                         List<Preset<T>> plist = pmanager.getPresets();\r
220                         succeed = !succeed ? presetAlign(msaws, plist) : succeed;\r
221                 }\r
222                 testMetadata(msaws);\r
223                 return succeed;\r
224         }\r
225         /**\r
226          * Call most of web services functions and check the output\r
227          * \r
228          * @param <T>\r
229          *            web service type\r
230          * @param msaws\r
231          * @throws UnsupportedRuntimeException\r
232          *             is thrown if the connection to a web service was made, but\r
233          *             the web service is not functional. e.g. when native\r
234          *             executable does not exists for a server platform\r
235          */\r
236         @SuppressWarnings("unchecked")\r
237         private <T> boolean checkService(JABAService wservice, Services service) {\r
238                 try {\r
239                         if (wservice == null) {\r
240                                 throw new NullPointerException("JABAService instance must be provided!");\r
241                         }\r
242 \r
243                         if (wservice instanceof MsaWS) {\r
244                                 return testMsaWS((MsaWS<T>) wservice, service);\r
245                         } else if (wservice instanceof SequenceAnnotation) {\r
246                                 return testSequenceAnnotationWS(\r
247                                                 (SequenceAnnotation<T>) wservice, service);\r
248                         } else {\r
249                                 throw new UnsupportedOperationException("The service: " + wservice.getClass() + " is not supported! ");\r
250                         }\r
251                 } catch (Exception e) {\r
252                         reportException(e);\r
253                         return false;\r
254                 }\r
255         }\r
256 \r
257         private <T> boolean testSequenceAnnotationWS(\r
258                         SequenceAnnotation<T> wservice, Services service) throws Exception {\r
259                 writer.print("Calling analyse.........");\r
260 \r
261                 List<FastaSequence> input = loadSeqs(2);\r
262                 if (service == Services.AAConWS ) {\r
263                         input = loadAlignment();\r
264                 } else if (service == Services.RNAalifoldWS) {\r
265                         input = loadRNAAlignment();\r
266                 }\r
267                 boolean success = testDefaultAnalyse(input, wservice, null, null);\r
268 \r
269                 PresetManager<T> presetman = wservice.getPresets();\r
270                 if (presetman != null) {\r
271                         List<Preset<T>> presets = presetman.getPresets();\r
272                         if (presets != null && !presets.isEmpty()) {\r
273                                 Preset<T> preset = presets.get(0);\r
274                                 writer.print("Calling analyse with Preset.........");\r
275                                 success = testDefaultAnalyse(input, wservice, preset, null);\r
276                         }\r
277                 }\r
278                 testMetadata(wservice);\r
279                 return success;\r
280         }\r
281 \r
282         private <T> boolean testDefaultAnalyse(List<FastaSequence> fastalist,\r
283                         SequenceAnnotation<T> wsproxy, Preset<T> preset,\r
284                         List<Option<T>> customOptions) throws Exception {\r
285 \r
286                 ScoreManager scores = null;\r
287 \r
288                 String jobId = null;\r
289                 if (customOptions != null) {\r
290                         jobId = wsproxy.customAnalize(fastalist, customOptions);\r
291                 } else if (preset != null) {\r
292                         jobId = wsproxy.presetAnalize(fastalist, preset);\r
293                 } else {\r
294                         jobId = wsproxy.analize(fastalist);\r
295                 }\r
296                 Thread.sleep(1000);\r
297                 scores = wsproxy.getAnnotation(jobId);\r
298                 if (scores != null) {\r
299                         writer.println(OK);\r
300                 }\r
301 \r
302                 return scores != null;\r
303         }\r
304 \r
305         private void reportException(Exception e) {\r
306                 writer.println(FAILED);\r
307                 writer.println("Exception while waiting for results. "\r
308                                 + "Exception details are below:");\r
309                 writer.println(e.getLocalizedMessage());\r
310                 e.printStackTrace(writer);\r
311         }\r
312 \r
313         private <T> void testMetadata(Metadata<T> msaws)\r
314                         throws UnsupportedRuntimeException {\r
315 \r
316                 writer.print("Querying presets...");\r
317                 PresetManager<T> pmanager = msaws.getPresets();\r
318                 if (pmanager != null && pmanager.getPresets().size() > 0) {\r
319                         writer.println(OK);\r
320                 } else {\r
321                         writer.println(UNSUPPORTED);\r
322                 }\r
323 \r
324                 writer.print("Querying Parameters...");\r
325                 RunnerConfig<T> options = msaws.getRunnerOptions();\r
326                 if (options != null && options.getArguments().size() > 0) {\r
327                         writer.println(OK);\r
328                 } else {\r
329                         writer.println(UNSUPPORTED);\r
330                 }\r
331 \r
332                 writer.print("Querying Limits...");\r
333                 LimitsManager<T> limits = msaws.getLimits();\r
334                 if (limits != null && limits.getLimits().size() > 0) {\r
335                         writer.println(OK);\r
336                         // writer.println("Limits details: \n" + limits.toString());\r
337                 } else {\r
338                         writer.println(UNSUPPORTED);\r
339                 }\r
340 \r
341                 writer.print("Querying Local Engine Limits...");\r
342                 Limit<T> localLimit = msaws\r
343                                 .getLimit(PresetManager.LOCAL_ENGINE_LIMIT_PRESET);\r
344                 if (localLimit != null) {\r
345                         writer.println(OK);\r
346                 } else {\r
347                         writer.println(UNSUPPORTED);\r
348                 }\r
349         }\r
350 \r
351         /**\r
352          * Align using default settings\r
353          * \r
354          * @param <T>\r
355          * @param msaws\r
356          * @throws UnsupportedRuntimeException\r
357          */\r
358         private <T> boolean testDefaultAlignment(MsaWS<T> msaws, Services service) throws Exception {\r
359                 writer.print("Testing alignment with default parameters:");\r
360                 Alignment al = null;\r
361                 boolean succeed = false;\r
362                 String taskId;\r
363 \r
364                 if (service == Services.JpredWS) {\r
365                         taskId = msaws.align(loadAlignment());\r
366                 } else {\r
367                         taskId = msaws.align(loadSeqs(2));\r
368                 }\r
369                 writer.print("\nQuerying job status...");\r
370                 JobStatus status = msaws.getJobStatus(taskId);\r
371                 while (status != JobStatus.FINISHED) {\r
372                         Thread.sleep(1000);\r
373                         status = msaws.getJobStatus(taskId);\r
374                 }\r
375                 writer.println(OK);\r
376                 writer.print("Retrieving results...");\r
377                 al = msaws.getResult(taskId);\r
378                 succeed = true;\r
379                 if (al != null) {\r
380                         writer.println(OK);\r
381                 }\r
382                 return succeed;\r
383         }\r
384         /**\r
385          * Test JWS2 web services\r
386          * \r
387          * @param <T>\r
388          *            web service type\r
389          * @param args\r
390          *            -h=<Your web application server host name, port and JWS2\r
391          *            context path>\r
392          * \r
393          *            -s=<ServiceName> which is optional. If service name is not\r
394          *            provided then all known JWS2 web services are tested\r
395          * @throws IOException\r
396          */\r
397         public static <T> void main(String[] args) throws IOException {\r
398 \r
399                 if (args == null || args.length < 1) {\r
400                         WSTester.printUsage();\r
401                         System.exit(0);\r
402                 }\r
403                 String host = CmdHelper.getHost(args);\r
404                 String serviceName = CmdHelper.getServiceName(args);\r
405                 if (!Jws2Client.validURL(host)) {\r
406                         System.err.println("<host_and_context> parameter is not provided or is incorrect!");\r
407                         System.exit(1);\r
408                 }\r
409                 WSTester tester = new WSTester(host, new PrintWriter(System.out, true));\r
410 \r
411                 if (serviceName != null) {\r
412                         Services service = Services.getService(serviceName);\r
413                         if (service == null) {\r
414                                 tester.writer.println("Service '" + serviceName + "' is not supported. Valid values are: "\r
415                                                 + Arrays.toString(Services.values()));\r
416                                 tester.writer.println();\r
417                                 printUsage();\r
418                                 System.exit(1);\r
419                         }\r
420                         tester.checkService(service);\r
421                         System.exit(0);\r
422                 }\r
423 \r
424                 tester.writer.println("<ServiceName> is not provided checking all known services...");\r
425 \r
426                 for (Services serv : Services.values()) {\r
427                         tester.writer.println();\r
428                         tester.checkService(serv);\r
429                 }\r
430 \r
431         }\r
432 \r
433         /**\r
434          * Test JABA web service\r
435          * \r
436          * @param service\r
437          *            the service to test\r
438          * @return true if the service works as expected, false otherwise\r
439          * @throws WebServiceException\r
440          * @throws ConnectException\r
441          */\r
442         public boolean checkService(Services service) throws ConnectException,\r
443                         WebServiceException {\r
444                 JABAService ws = Jws2Client.connect(hostname, service);\r
445                 if (ws == null) {\r
446                         String line = "Cannot estabilish the connection to host " + hostname + " with service ";\r
447                         writer.println(line + service.toString());\r
448                         return false;\r
449                 }\r
450                 boolean succeed = false;\r
451                 try {\r
452                         writer.println("Checking service " + service.toString());\r
453                         succeed = checkService(ws, service);\r
454                 } finally {\r
455                         FileUtil.closeSilently(((Closeable) ws));\r
456                 }\r
457                 reportResults(service, succeed);\r
458                 return succeed;\r
459         }\r
460 \r
461         private void reportResults(Services serv, boolean succeed) {\r
462                 if (succeed) {\r
463                         writer.println("Check is completed. The Service " + serv + " IS WORKING\n");\r
464                 } else {\r
465                         writer.println("Check is aborted. The Service " + serv + " HAS SOME PROBLEMS\n");\r
466                 }\r
467         }\r
468 }\r