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