More work to disorder prediction client & services.
[jabaws.git] / webservices / compbio / ws / client / Jws2Client.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.inputkey;\r
23 import static compbio.ws.client.Constraints.limitList;\r
24 import static compbio.ws.client.Constraints.outputkey;\r
25 import static compbio.ws.client.Constraints.paramFile;\r
26 import static compbio.ws.client.Constraints.paramList;\r
27 import static compbio.ws.client.Constraints.presetList;\r
28 import static compbio.ws.client.Constraints.presetkey;\r
29 import static compbio.ws.client.Constraints.pseparator;\r
30 import static compbio.ws.client.Constraints.servicekey;\r
31 \r
32 import java.io.Closeable;\r
33 import java.io.File;\r
34 import java.io.FileInputStream;\r
35 import java.io.IOException;\r
36 import java.io.PrintWriter;\r
37 import java.io.Writer;\r
38 import java.net.MalformedURLException;\r
39 import java.net.URL;\r
40 import java.util.Arrays;\r
41 import java.util.List;\r
42 import java.util.logging.Level;\r
43 import java.util.logging.Logger;\r
44 \r
45 import javax.xml.namespace.QName;\r
46 import javax.xml.ws.Service;\r
47 import javax.xml.ws.WebServiceException;\r
48 \r
49 import compbio.data.msa.JABAService;\r
50 import compbio.data.msa.Metadata;\r
51 import compbio.data.msa.MsaWS;\r
52 import compbio.data.msa.SequenceAnnotation;\r
53 import compbio.data.sequence.Alignment;\r
54 import compbio.data.sequence.FastaSequence;\r
55 import compbio.data.sequence.ScoreManager;\r
56 import compbio.data.sequence.SequenceUtil;\r
57 import compbio.data.sequence.UnknownFileFormatException;\r
58 import compbio.metadata.JobSubmissionException;\r
59 import compbio.metadata.Option;\r
60 import compbio.metadata.Preset;\r
61 import compbio.metadata.ResultNotAvailableException;\r
62 import compbio.metadata.WrongParameterException;\r
63 \r
64 /**\r
65  * A command line client for JAva Bioinformatics Analysis Web Services\r
66  * \r
67  * @author pvtroshin\r
68  * @version 1.0\r
69  */\r
70 public class Jws2Client {\r
71 \r
72         /*\r
73          * TODO Use java.util.Logger instead of log4j logger to reduce the size of\r
74          * the client package\r
75          */\r
76         private static final Logger log = Logger.getLogger(Jws2Client.class\r
77                         .getCanonicalName());\r
78 \r
79         // JABAWS version 1.0 service name\r
80         static final String QUALIFIED_SERVICE_NAME = "http://msa.data.compbio/01/01/2010/";\r
81 \r
82         // JABAWS version 2.0 service name\r
83         static final String V2_QUALIFIED_SERVICE_NAME = "http://msa.data.compbio/01/12/2010/";\r
84 \r
85         /**\r
86          * Attempt to construct the URL object from the string\r
87          * \r
88          * @param urlstr\r
89          * @return true if it succeed false otherwise\r
90          */\r
91         public static boolean validURL(String urlstr) {\r
92                 try {\r
93                         if (urlstr == null || urlstr.trim().length() == 0) {\r
94                                 return false;\r
95                         }\r
96                         new URL(urlstr);\r
97                 } catch (MalformedURLException e) {\r
98                         return false;\r
99                 }\r
100                 return true;\r
101         }\r
102 \r
103         /**\r
104          * Connects to the service and do the job as requested, if something goes\r
105          * wrong reports or/and prints usage help.\r
106          * \r
107          * @param <T>\r
108          *            web service type\r
109          * @param cmd\r
110          *            command line options\r
111          * @throws IOException\r
112          */\r
113         <T> Jws2Client(String[] cmd) throws IOException {\r
114 \r
115                 String hostname = CmdHelper.getHost(cmd);\r
116                 if (hostname == null) {\r
117                         System.out.println("Host name is not provided!");\r
118                         printUsage(1);\r
119                 }\r
120 \r
121                 if (!validURL(hostname)) {\r
122                         System.out.println("Host name is not valid!");\r
123                         printUsage(1);\r
124                 }\r
125                 String serviceName = CmdHelper.getServiceName(cmd);\r
126                 if (serviceName == null) {\r
127                         System.out.println("Service name is no provided!");\r
128                         printUsage(1);\r
129                 }\r
130                 Services service = Services.getService(serviceName);\r
131                 if (service == null) {\r
132                         System.out.println("Service " + serviceName\r
133                                         + " is no supported! Valid values are: "\r
134                                         + Arrays.toString(Services.values()));\r
135                         printUsage(1);\r
136                 }\r
137                 File inputFile = IOHelper.getFile(cmd, inputkey, true);\r
138                 File outFile = IOHelper.getFile(cmd, outputkey, false);\r
139                 File parametersFile = IOHelper.getFile(cmd, paramFile, true);\r
140                 String presetName = CmdHelper.getPresetName(cmd);\r
141 \r
142                 Metadata<T> msaws = (Metadata<T>) connect(hostname, service);\r
143                 Preset<T> preset = null;\r
144                 if (presetName != null) {\r
145                         preset = MetadataHelper.getPreset(msaws, presetName);\r
146                 }\r
147                 List<Option<T>> customOptions = null;\r
148                 if (parametersFile != null) {\r
149                         List<String> prms = IOHelper.loadParameters(parametersFile);\r
150                         customOptions = MetadataHelper.processParameters(prms,\r
151                                         msaws.getRunnerOptions());\r
152                 }\r
153                 Alignment alignment = null;\r
154                 if (inputFile != null) {\r
155                         Writer writer = null;\r
156                         if (outFile != null) {\r
157                                 writer = IOHelper.getWriter(outFile);\r
158                         } else {\r
159                                 // this stream is going to be closed later which is fine as\r
160                                 // std.out will not be\r
161                                 writer = new PrintWriter(System.out, true);\r
162                         }\r
163                         if (service.getServiceType() == SequenceAnnotation.class) {\r
164                                 ScoreManager result = analize(inputFile,\r
165                                                 ((SequenceAnnotation<T>) msaws), preset, customOptions);\r
166 \r
167                                 IOHelper.writeOut(writer, result);\r
168                         } else {\r
169                                 alignment = align(inputFile, (MsaWS<T>) msaws, preset,\r
170                                                 customOptions);\r
171                                 IOHelper.writeOut(writer, alignment);\r
172                         }\r
173                         writer.close();\r
174                 }\r
175 \r
176                 boolean listParameters = CmdHelper.listParameters(cmd);\r
177                 if (listParameters) {\r
178                         System.out.println(MetadataHelper.getParametersList(msaws));\r
179                 }\r
180                 boolean listPreset = CmdHelper.listPresets(cmd);\r
181                 if (listPreset) {\r
182                         System.out.println(MetadataHelper.getPresetList(msaws));\r
183                 }\r
184                 boolean listLimits = CmdHelper.listLimits(cmd);\r
185                 if (listLimits) {\r
186                         System.out.println(MetadataHelper.getLimits(msaws));\r
187                 }\r
188                 log.fine("Disconnecting...");\r
189                 ((Closeable) msaws).close();\r
190                 log.fine("Disconnected successfully!");\r
191         }\r
192         /**\r
193          * Calculate conservation for sequences loaded from the file\r
194          * \r
195          * @param wsproxy\r
196          *            a web service proxy\r
197          * @param file\r
198          *            the file to read the results from\r
199          * @param preset\r
200          *            Preset to use optional\r
201          * @param customOptions\r
202          *            the list of options\r
203          * @return Set<Score> the conservation scores\r
204          * @throws UnknownFileFormatException\r
205          */\r
206         static <T> ScoreManager analize(List<FastaSequence> fastalist,\r
207                         SequenceAnnotation<T> wsproxy, Preset<T> preset,\r
208                         List<Option<T>> customOptions) {\r
209 \r
210                 ScoreManager scores = null;\r
211                 try {\r
212                         String jobId = null;\r
213                         if (customOptions != null && preset != null) {\r
214                                 System.out\r
215                                                 .println("WARN: Parameters (-f) are defined together with a preset (-r) ignoring preset!");\r
216                         }\r
217                         if (customOptions != null) {\r
218                                 jobId = wsproxy.customAnalize(fastalist, customOptions);\r
219                         } else if (preset != null) {\r
220                                 jobId = wsproxy.presetAnalize(fastalist, preset);\r
221                         } else {\r
222                                 jobId = wsproxy.analize(fastalist);\r
223                         }\r
224                         System.out.println("\n\ncalling analise.........");\r
225                         Thread.sleep(1000);\r
226                         scores = wsproxy.getAnnotation(jobId);\r
227 \r
228                 } catch (JobSubmissionException e) {\r
229                         System.err\r
230                                         .println("Exception while submitting job to a web server. "\r
231                                                         + "Exception details are below:");\r
232                         e.printStackTrace();\r
233                 } catch (ResultNotAvailableException e) {\r
234                         System.err.println("Exception while waiting for results. "\r
235                                         + "Exception details are below:");\r
236                         e.printStackTrace();\r
237                 } catch (InterruptedException e) {\r
238                         // ignore and propagate an interruption\r
239                         Thread.currentThread().interrupt();\r
240                         System.err.println("Exception while waiting for results. "\r
241                                         + "Exception details are below:");\r
242                         e.printStackTrace();\r
243                 } catch (WrongParameterException e) {\r
244                         System.err\r
245                                         .println("Exception while parsing the web method input parameters. "\r
246                                                         + "Exception details are below:");\r
247                         e.printStackTrace();\r
248                 }\r
249                 return scores;\r
250 \r
251         }\r
252 \r
253         /**\r
254          * Calculate conservation for sequences loaded from the file\r
255          * \r
256          * @param wsproxy\r
257          *            a web service proxy\r
258          * @param file\r
259          *            the file to read the results from\r
260          * @param preset\r
261          *            Preset to use optional\r
262          * @param customOptions\r
263          *            the list of options\r
264          * @return Set<Score> the conservation scores\r
265          * @throws IOException\r
266          * @throws UnknownFileFormatException\r
267          */\r
268         static <T> ScoreManager analize(File file, SequenceAnnotation<T> wsproxy,\r
269                         Preset<T> preset, List<Option<T>> customOptions) {\r
270                 List<FastaSequence> fastalist = null;\r
271                 try {\r
272                         fastalist = SequenceUtil.openInputStream(file.getAbsolutePath());\r
273                         assert !fastalist.isEmpty() : "Input is empty!";\r
274                 } catch (IOException e) {\r
275                         System.err\r
276                                         .println("Exception while reading the input file. "\r
277                                                         + "Check that the input file contains a list of fasta formatted sequences! "\r
278                                                         + "Exception details are below:");\r
279                         e.printStackTrace();\r
280                 } catch (UnknownFileFormatException e) {\r
281                         System.err\r
282                                         .println("Exception while attempting to read the input file "\r
283                                                         + "Exception details are below:");\r
284                         System.out.println(e.getMessage());\r
285                         e.printStackTrace();\r
286                 }\r
287                 return analize(fastalist, wsproxy, preset, customOptions);\r
288         }\r
289         /**\r
290          * Connects to a web service by the host and the service name\r
291          * \r
292          * @param T\r
293          *            web service type\r
294          * @param host\r
295          * @param service\r
296          * @return MsaWS<T>\r
297          * @throws WebServiceException\r
298          */\r
299         public static JABAService connect(String host, Services service)\r
300                         throws WebServiceException {\r
301                 URL url = null;\r
302                 log.log(Level.FINE, "Attempting to connect...");\r
303                 try {\r
304                         url = new URL(host + "/" + service.toString() + "?wsdl");\r
305                 } catch (MalformedURLException e) {\r
306                         e.printStackTrace();\r
307                         // ignore as the host name is already verified\r
308                 }\r
309                 Service serv = null;\r
310                 try {\r
311                         serv = service.getService(url, QUALIFIED_SERVICE_NAME);\r
312                 } catch (WebServiceException wse) {\r
313                         System.out.println("Connecting to JABAWS version 2 service");\r
314                         if (isV2service(wse)) {\r
315                                 serv = service.getService(url, V2_QUALIFIED_SERVICE_NAME);\r
316                         }\r
317                 }\r
318                 if (serv == null) {\r
319                         System.err.println("Could not connect to " + url\r
320                                         + " the server is down?");\r
321                         // FIXME\r
322                 }\r
323                 JABAService serviceIF = service.getInterface(serv);\r
324                 log.log(Level.INFO, "Connected successfully!");\r
325 \r
326                 return serviceIF;\r
327         }\r
328 \r
329         static boolean isV2service(WebServiceException wse) {\r
330                 String message = wse.getMessage();\r
331                 int idx = message.indexOf("not a valid service");\r
332                 if (idx > 0) {\r
333                         if (message.substring(idx).contains(V2_QUALIFIED_SERVICE_NAME)) {\r
334                                 return true;\r
335                         }\r
336                 }\r
337                 return false;\r
338         }\r
339 \r
340         public static compbio.data.msa.RegistryWS connectToRegistry(String host)\r
341                         throws WebServiceException {\r
342                 URL url = null;\r
343                 String service = "RegistryWS";\r
344                 log.log(Level.FINE, "Attempting to connect...");\r
345 \r
346                 try {\r
347                         url = new URL(host + "/" + service + "?wsdl");\r
348                 } catch (MalformedURLException e) {\r
349                         e.printStackTrace();\r
350                         // ignore as the host name is already verified\r
351                 }\r
352                 QName qname = new QName(V2_QUALIFIED_SERVICE_NAME, service);\r
353                 Service serv = Service.create(url, qname);\r
354 \r
355                 if (serv == null) {\r
356                         System.err.println("Could not connect to " + url\r
357                                         + " the server is down?");\r
358                 }\r
359 \r
360                 QName portName = new QName(serv.getServiceName().getNamespaceURI(),\r
361                                 service + "Port");\r
362                 compbio.data.msa.RegistryWS serviceIF = serv.getPort(portName,\r
363                                 compbio.data.msa.RegistryWS.class);\r
364 \r
365                 log.log(Level.INFO, "Connected to " + service + " successfully!");\r
366 \r
367                 return serviceIF;\r
368         }\r
369 \r
370         /**\r
371          * Align sequences from the file using MsaWS\r
372          * \r
373          * @param <T>\r
374          *            web service type e.g. Clustal\r
375          * @param file\r
376          *            to write the resulting alignment to\r
377          * @param msaws\r
378          *            MsaWS required\r
379          * @param preset\r
380          *            Preset to use optional\r
381          * @param customOptions\r
382          *            file which contains new line separated list of options\r
383          * @return Alignment\r
384          */\r
385         static <T> Alignment align(File file, MsaWS<T> msaws, Preset<T> preset,\r
386                         List<Option<T>> customOptions) {\r
387                 FileInputStream instream = null;\r
388                 List<FastaSequence> fastalist = null;\r
389                 Alignment alignment = null;\r
390                 try {\r
391                         instream = new FileInputStream(file);\r
392                         fastalist = SequenceUtil.readFasta(instream);\r
393                         instream.close();\r
394                         String jobId = null;\r
395                         if (customOptions != null && preset != null) {\r
396                                 System.out\r
397                                                 .println("WARN: Parameters (-f) are defined together with a preset (-r) ignoring preset!");\r
398                         }\r
399                         if (customOptions != null) {\r
400                                 jobId = msaws.customAlign(fastalist, customOptions);\r
401                         } else if (preset != null) {\r
402                                 jobId = msaws.presetAlign(fastalist, preset);\r
403                         } else {\r
404                                 jobId = msaws.align(fastalist);\r
405                         }\r
406                         System.out.println("\n\ncalling align.........");\r
407                         Thread.sleep(1000);\r
408                         alignment = msaws.getResult(jobId);\r
409 \r
410                 } catch (IOException e) {\r
411                         System.err\r
412                                         .println("Exception while reading the input file. "\r
413                                                         + "Check that the input file contains a list of fasta formatted sequences! "\r
414                                                         + "Exception details are below:");\r
415                         e.printStackTrace();\r
416                 } catch (JobSubmissionException e) {\r
417                         System.err\r
418                                         .println("Exception while submitting job to a web server. "\r
419                                                         + "Exception details are below:");\r
420                         e.printStackTrace();\r
421                 } catch (ResultNotAvailableException e) {\r
422                         System.err.println("Exception while waiting for results. "\r
423                                         + "Exception details are below:");\r
424                         e.printStackTrace();\r
425                 } catch (InterruptedException ignored) {\r
426                         // ignore and propagate an interruption\r
427                         Thread.currentThread().interrupt();\r
428                 } catch (WrongParameterException e) {\r
429                         e.printStackTrace();\r
430                 } finally {\r
431                         if (instream != null) {\r
432                                 try {\r
433                                         instream.close();\r
434                                 } catch (IOException ignored) {\r
435                                         // ignore\r
436                                 }\r
437                         }\r
438                 }\r
439                 return alignment;\r
440         }\r
441 \r
442         /**\r
443          * Prints Jws2Client usage information to standard out\r
444          * \r
445          * @param exitStatus\r
446          */\r
447         static void printUsage(int exitStatus) {\r
448                 System.out.println();\r
449                 System.out.println("Usage: <Class or Jar file name> " + hostkey\r
450                                 + pseparator + "host_and_context " + servicekey + pseparator\r
451                                 + "serviceName ACTION [OPTIONS] ");\r
452                 System.out.println();\r
453                 System.out\r
454                                 .println(hostkey\r
455                                                 + pseparator\r
456                                                 + "<host_and_context> - a full URL to the JWS2 web server including context path e.g. http://10.31.1.159:8080/ws");\r
457                 System.out.println(servicekey + pseparator + "<ServiceName> - one of "\r
458                                 + Arrays.toString(Services.values()));\r
459                 System.out.println();\r
460                 System.out.println("ACTIONS: ");\r
461                 System.out\r
462                                 .println(inputkey\r
463                                                 + pseparator\r
464                                                 + "<inputFile> - full path to fasta formatted sequence file, from which to align sequences");\r
465                 System.out.println(paramList\r
466                                 + " - lists parameters supported by web service");\r
467                 System.out.println(presetList\r
468                                 + " - lists presets supported by web service");\r
469                 System.out.println(limitList + " - lists web services limits");\r
470                 System.out\r
471                                 .println("Please note that if input file is specified other actions are ignored");\r
472 \r
473                 System.out.println();\r
474                 System.out.println("OPTIONS (only for use with -i action):");\r
475 \r
476                 System.out.println(presetkey + pseparator\r
477                                 + "<presetName> - name of the preset to use");\r
478                 System.out\r
479                                 .println(outputkey\r
480                                                 + pseparator\r
481                                                 + "<outputFile> - full path to the file where to write an alignment");\r
482                 System.out\r
483                                 .println("-f=<parameterInputFile> - the name of the file with the list of parameters to use.");\r
484                 System.out\r
485                                 .println("Please note that -r and -f options cannot be used together. "\r
486                                                 + "Alignment is done with either preset or a parameters from the file, but not both!");\r
487 \r
488                 System.exit(exitStatus);\r
489         }\r
490 \r
491         /**\r
492          * Starts command line client, if no parameter are supported print help. Two\r
493          * parameters are required for successful call the JWS2 host name and a\r
494          * service name.\r
495          * \r
496          * @param args\r
497          *            Usage: <Class or Jar file name> -h=host_and_context\r
498          *            -s=serviceName ACTION [OPTIONS]\r
499          * \r
500          *            -h=<host_and_context> - a full URL to the JWS2 web server\r
501          *            including context path e.g. http://10.31.1.159:8080/ws\r
502          * \r
503          *            -s=<ServiceName> - one of [MafftWS, MuscleWS, ClustalWS,\r
504          *            TcoffeeWS, ProbconsWS] ACTIONS:\r
505          * \r
506          *            -i=<inputFile> - full path to fasta formatted sequence file,\r
507          *            from which to align sequences\r
508          * \r
509          *            -parameters - lists parameters supported by web service\r
510          * \r
511          *            -presets - lists presets supported by web service\r
512          * \r
513          *            -limits - lists web services limits Please note that if input\r
514          *            file is specified other actions are ignored\r
515          * \r
516          *            OPTIONS: (only for use with -i action):\r
517          * \r
518          *            -r=<presetName> - name of the preset to use\r
519          * \r
520          *            -o=<outputFile> - full path to the file where to write an\r
521          *            alignment -f=<parameterInputFile> - the name of the file with\r
522          *            the list of parameters to use. Please note that -r and -f\r
523          *            options cannot be used together. Alignment is done with either\r
524          *            preset or a parameters from the file, but not both!\r
525          * \r
526          */\r
527         public static void main(String[] args) {\r
528 \r
529                 if (args == null) {\r
530                         printUsage(1);\r
531                 }\r
532                 if (args.length < 2) {\r
533                         System.out.println("Host and service names are required!");\r
534                         printUsage(1);\r
535                 }\r
536 \r
537                 try {\r
538                         new Jws2Client(args);\r
539                 } catch (IOException e) {\r
540                         log.log(Level.SEVERE, "IOException in client! " + e.getMessage(),\r
541                                         e.getCause());\r
542                         System.err.println("Cannot write output file! Stack trace: ");\r
543                         e.printStackTrace();\r
544                 }\r
545         }\r
546 }\r