Disembl and Jronn web services work. Modified to produce raw scores Globplot script...
[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.HashSet;\r
41 import java.util.List;\r
42 import java.util.Map;\r
43 import java.util.logging.Level;\r
44 import java.util.logging.Logger;\r
45 \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.Score;\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          * Use java.util.Logger instead of log4j logger to reduce the size of the\r
74          * 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                         OutputStream outStream = null;\r
156                         if (outFile != null) {\r
157                                 outStream = IOHelper.getOutStream(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                                 outStream = System.out;\r
162                         }\r
163                         if (service == Services.AAConWS) {\r
164                                 Map<String, HashSet<Score>> result = analize(inputFile,\r
165                                                 ((SequenceAnnotation<T>) msaws), preset, customOptions);\r
166                                 IOHelper.writeOut(outStream, result);\r
167                         } else {\r
168                                 alignment = align(inputFile, (MsaWS<T>) msaws, preset,\r
169                                                 customOptions);\r
170                                 IOHelper.writeOut(outStream, alignment);\r
171                         }\r
172 \r
173                         // stream is closed in the method no need to close it here\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         <T> Map<String, HashSet<Score>> analize(File file,\r
207                         SequenceAnnotation<T> wsproxy, Preset<T> preset,\r
208                         List<Option<T>> customOptions) {\r
209 \r
210                 List<FastaSequence> fastalist = null;\r
211                 Map<String, HashSet<Score>> scores = null;\r
212                 try {\r
213                         fastalist = SequenceUtil.openInputStream(file.getAbsolutePath());\r
214 \r
215                         String jobId = null;\r
216                         if (customOptions != null && preset != null) {\r
217                                 System.out\r
218                                                 .println("WARN: Parameters (-f) are defined together with a preset (-r) ignoring preset!");\r
219                         }\r
220                         if (customOptions != null) {\r
221                                 jobId = wsproxy.customAnalize(fastalist, customOptions);\r
222                         } else if (preset != null) {\r
223                                 jobId = wsproxy.presetAnalize(fastalist, preset);\r
224                         } else {\r
225                                 jobId = wsproxy.analize(fastalist);\r
226                         }\r
227                         Thread.sleep(1000);\r
228                         scores = wsproxy.getAnnotation(jobId);\r
229 \r
230                 } catch (IOException e) {\r
231                         System.err\r
232                                         .println("Exception while reading the input file. "\r
233                                                         + "Check that the input file contains a list of fasta formatted sequences! "\r
234                                                         + "Exception details are below:");\r
235                         e.printStackTrace();\r
236                 } catch (JobSubmissionException e) {\r
237                         System.err\r
238                                         .println("Exception while submitting job to a web server. "\r
239                                                         + "Exception details are below:");\r
240                         e.printStackTrace();\r
241                 } catch (ResultNotAvailableException e) {\r
242                         System.err.println("Exception while waiting for results. "\r
243                                         + "Exception details are below:");\r
244                         e.printStackTrace();\r
245                 } catch (InterruptedException ignored) {\r
246                         // ignore and propagate an interruption\r
247                         Thread.currentThread().interrupt();\r
248                 } catch (WrongParameterException e) {\r
249                         System.err\r
250                                         .println("Exception while parsing the web method input parameters. "\r
251                                                         + "Exception details are below:");\r
252                         e.printStackTrace();\r
253                 } catch (UnknownFileFormatException e) {\r
254                         System.err\r
255                                         .println("Exception while attempting to read the input file "\r
256                                                         + "Exception details are below:");\r
257                         System.out.println(e.getMessage());\r
258                         e.printStackTrace();\r
259                 }\r
260                 return scores;\r
261         }\r
262 \r
263         /**\r
264          * Connects to a web service by the host and the service name\r
265          * \r
266          * @param T\r
267          *            web service type\r
268          * @param host\r
269          * @param service\r
270          * @return MsaWS<T>\r
271          * @throws WebServiceException\r
272          */\r
273         public static JABAService connect(String host, Services service)\r
274                         throws WebServiceException {\r
275                 URL url = null;\r
276                 log.log(Level.FINE, "Attempting to connect...");\r
277                 try {\r
278                         url = new URL(host + "/" + service.toString() + "?wsdl");\r
279                 } catch (MalformedURLException e) {\r
280                         e.printStackTrace();\r
281                         // ignore as the host name is already verified\r
282                 }\r
283                 Service serv = null;\r
284                 try {\r
285                         serv = service.getService(url, QUALIFIED_SERVICE_NAME);\r
286                 } catch (WebServiceException wse) {\r
287                         System.out.println("Conecting to JABAWS version 2 service");\r
288                         if (isV2service(wse)) {\r
289                                 serv = service.getService(url, V2_QUALIFIED_SERVICE_NAME);\r
290                         }\r
291                 }\r
292                 JABAService serviceIF = service.getInterface(serv);\r
293                 log.log(Level.FINE, "Connected successfully!");\r
294 \r
295                 return serviceIF;\r
296         }\r
297 \r
298         static boolean isV2service(WebServiceException wse) {\r
299                 String message = wse.getMessage();\r
300                 int idx = message.indexOf("not a valid service");\r
301                 if (idx > 0) {\r
302                         if (message.substring(idx).contains(V2_QUALIFIED_SERVICE_NAME)) {\r
303                                 return true;\r
304                         }\r
305                 }\r
306                 return false;\r
307         }\r
308 \r
309         /**\r
310          * Align sequences from the file using MsaWS\r
311          * \r
312          * @param <T>\r
313          *            web service type e.g. Clustal\r
314          * @param file\r
315          *            to write the resulting alignment to\r
316          * @param msaws\r
317          *            MsaWS required\r
318          * @param preset\r
319          *            Preset to use optional\r
320          * @param customOptions\r
321          *            file which contains new line separated list of options\r
322          * @return Alignment\r
323          */\r
324         static <T> Alignment align(File file, MsaWS<T> msaws, Preset<T> preset,\r
325                         List<Option<T>> customOptions) {\r
326                 FileInputStream instream = null;\r
327                 List<FastaSequence> fastalist = null;\r
328                 Alignment alignment = null;\r
329                 try {\r
330                         instream = new FileInputStream(file);\r
331                         fastalist = SequenceUtil.readFasta(instream);\r
332                         instream.close();\r
333                         String jobId = null;\r
334                         if (customOptions != null && preset != null) {\r
335                                 System.out\r
336                                                 .println("WARN: Parameters (-f) are defined together with a preset (-r) ignoring preset!");\r
337                         }\r
338                         if (customOptions != null) {\r
339                                 jobId = msaws.customAlign(fastalist, customOptions);\r
340                         } else if (preset != null) {\r
341                                 jobId = msaws.presetAlign(fastalist, preset);\r
342                         } else {\r
343                                 jobId = msaws.align(fastalist);\r
344                         }\r
345                         Thread.sleep(1000);\r
346                         alignment = msaws.getResult(jobId);\r
347 \r
348                 } catch (IOException e) {\r
349                         System.err\r
350                                         .println("Exception while reading the input file. "\r
351                                                         + "Check that the input file contains a list of fasta formatted sequences! "\r
352                                                         + "Exception details are below:");\r
353                         e.printStackTrace();\r
354                 } catch (JobSubmissionException e) {\r
355                         System.err\r
356                                         .println("Exception while submitting job to a web server. "\r
357                                                         + "Exception details are below:");\r
358                         e.printStackTrace();\r
359                 } catch (ResultNotAvailableException e) {\r
360                         System.err.println("Exception while waiting for results. "\r
361                                         + "Exception details are below:");\r
362                         e.printStackTrace();\r
363                 } catch (InterruptedException ignored) {\r
364                         // ignore and propagate an interruption\r
365                         Thread.currentThread().interrupt();\r
366                 } catch (WrongParameterException e) {\r
367                         e.printStackTrace();\r
368                 } finally {\r
369                         if (instream != null) {\r
370                                 try {\r
371                                         instream.close();\r
372                                 } catch (IOException ignored) {\r
373                                         // ignore\r
374                                 }\r
375                         }\r
376                 }\r
377                 return alignment;\r
378         }\r
379 \r
380         /**\r
381          * Prints Jws2Client usage information to standard out\r
382          * \r
383          * @param exitStatus\r
384          */\r
385         static void printUsage(int exitStatus) {\r
386                 System.out.println();\r
387                 System.out.println("Usage: <Class or Jar file name> " + hostkey\r
388                                 + pseparator + "host_and_context " + servicekey + pseparator\r
389                                 + "serviceName ACTION [OPTIONS] ");\r
390                 System.out.println();\r
391                 System.out\r
392                                 .println(hostkey\r
393                                                 + pseparator\r
394                                                 + "<host_and_context> - a full URL to the JWS2 web server including context path e.g. http://10.31.1.159:8080/ws");\r
395                 System.out.println(servicekey + pseparator + "<ServiceName> - one of "\r
396                                 + Arrays.toString(Services.values()));\r
397                 System.out.println();\r
398                 System.out.println("ACTIONS: ");\r
399                 System.out\r
400                                 .println(inputkey\r
401                                                 + pseparator\r
402                                                 + "<inputFile> - full path to fasta formatted sequence file, from which to align sequences");\r
403                 System.out.println(paramList\r
404                                 + " - lists parameters supported by web service");\r
405                 System.out.println(presetList\r
406                                 + " - lists presets supported by web service");\r
407                 System.out.println(limitList + " - lists web services limits");\r
408                 System.out\r
409                                 .println("Please note that if input file is specified other actions are ignored");\r
410 \r
411                 System.out.println();\r
412                 System.out.println("OPTIONS (only for use with -i action):");\r
413 \r
414                 System.out.println(presetkey + pseparator\r
415                                 + "<presetName> - name of the preset to use");\r
416                 System.out\r
417                                 .println(outputkey\r
418                                                 + pseparator\r
419                                                 + "<outputFile> - full path to the file where to write an alignment");\r
420                 System.out\r
421                                 .println("-f=<parameterInputFile> - the name of the file with the list of parameters to use.");\r
422                 System.out\r
423                                 .println("Please note that -r and -f options cannot be used together. "\r
424                                                 + "Alignment is done with either preset or a parameters from the file, but not both!");\r
425 \r
426                 System.exit(exitStatus);\r
427         }\r
428 \r
429         /**\r
430          * Starts command line client, if no parameter are supported print help. Two\r
431          * parameters are required for successfull call the JWS2 host name and a\r
432          * service name.\r
433          * \r
434          * @param args\r
435          *            Usage: <Class or Jar file name> -h=host_and_context\r
436          *            -s=serviceName ACTION [OPTIONS]\r
437          * \r
438          *            -h=<host_and_context> - a full URL to the JWS2 web server\r
439          *            including context path e.g. http://10.31.1.159:8080/ws\r
440          * \r
441          *            -s=<ServiceName> - one of [MafftWS, MuscleWS, ClustalWS,\r
442          *            TcoffeeWS, ProbconsWS] ACTIONS:\r
443          * \r
444          *            -i=<inputFile> - full path to fasta formatted sequence file,\r
445          *            from which to align sequences\r
446          * \r
447          *            -parameters - lists parameters supported by web service\r
448          * \r
449          *            -presets - lists presets supported by web service\r
450          * \r
451          *            -limits - lists web services limits Please note that if input\r
452          *            file is specified other actions are ignored\r
453          * \r
454          *            OPTIONS: (only for use with -i action):\r
455          * \r
456          *            -r=<presetName> - name of the preset to use\r
457          * \r
458          *            -o=<outputFile> - full path to the file where to write an\r
459          *            alignment -f=<parameterInputFile> - the name of the file with\r
460          *            the list of parameters to use. Please note that -r and -f\r
461          *            options cannot be used together. Alignment is done with either\r
462          *            preset or a parameters from the file, but not both!\r
463          * \r
464          */\r
465         public static void main(String[] args) {\r
466 \r
467                 if (args == null) {\r
468                         printUsage(1);\r
469                 }\r
470                 if (args.length < 2) {\r
471                         System.out.println("Host and service names are required!");\r
472                         printUsage(1);\r
473                 }\r
474 \r
475                 try {\r
476                         new Jws2Client(args);\r
477                 } catch (IOException e) {\r
478                         log.log(Level.SEVERE, "IOException in client! " + e.getMessage(),\r
479                                         e.getCause());\r
480                         System.err.println("Cannot write output file! Stack trace: ");\r
481                         e.printStackTrace();\r
482                 }\r
483         }\r
484 }\r