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