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