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