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