Next version of JABA
[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 java.io.BufferedReader;\r
22 import java.io.Closeable;\r
23 import java.io.File;\r
24 import java.io.FileInputStream;\r
25 import java.io.FileNotFoundException;\r
26 import java.io.FileOutputStream;\r
27 import java.io.FileReader;\r
28 import java.io.IOException;\r
29 import java.io.OutputStream;\r
30 import java.net.MalformedURLException;\r
31 import java.net.URL;\r
32 import java.util.ArrayList;\r
33 import java.util.Arrays;\r
34 import java.util.List;\r
35 import java.util.logging.Level;\r
36 import java.util.logging.Logger;\r
37 \r
38 import javax.xml.namespace.QName;\r
39 import javax.xml.ws.Service;\r
40 import javax.xml.ws.WebServiceException;\r
41 \r
42 import compbio.data.msa.MsaWS;\r
43 import compbio.data.sequence.Alignment;\r
44 import compbio.data.sequence.ClustalAlignmentUtil;\r
45 import compbio.data.sequence.FastaSequence;\r
46 import compbio.data.sequence.SequenceUtil;\r
47 import compbio.metadata.JobSubmissionException;\r
48 import compbio.metadata.Limit;\r
49 import compbio.metadata.LimitsManager;\r
50 import compbio.metadata.Option;\r
51 import compbio.metadata.Preset;\r
52 import compbio.metadata.PresetManager;\r
53 import compbio.metadata.ResultNotAvailableException;\r
54 import compbio.metadata.RunnerConfig;\r
55 import compbio.metadata.WrongParameterException;\r
56 \r
57 /**\r
58  * A command line client for JAva Bioinformatics Analysis Web Services\r
59  * \r
60  * @author pvtroshin\r
61  * @version 1.0\r
62  */\r
63 public class Jws2Client {\r
64 \r
65     /*\r
66      * Use java.util.Logger instead of log4j logger to reduce the size of the\r
67      * client package\r
68      */\r
69     private static final Logger log = Logger.getLogger(Jws2Client.class\r
70             .getCanonicalName());\r
71 \r
72     final static String pseparator = "=";\r
73 \r
74     // Parameters for required command line options\r
75     final static String hostkey = "-h";\r
76     final static String servicekey = "-s";\r
77 \r
78     // Actions\r
79     final static String inputkey = "-i";\r
80 \r
81     final static String paramList = "-parameters";\r
82     final static String presetList = "-presets";\r
83     final static String limitList = "-limits";\r
84 \r
85     // Options\r
86     final static String paramFile = "-f";\r
87     final static String outputkey = "-o";\r
88     final static String parameterkey = "-p";\r
89     final static String presetkey = "-r";\r
90 \r
91     //JABAWS version 1.0 service name\r
92     static final String qualifiedServiceName = "http://msa.data.compbio/01/01/2010/";\r
93 \r
94     /**\r
95      * Searches the command line keys in the array of parameters\r
96      * \r
97      * @param cmd\r
98      *            command line options\r
99      * @return true is the list of Parameters is requested, false otherwise\r
100      */\r
101     private boolean listParameters(String[] cmd) {\r
102         return keyFound(cmd, paramList);\r
103     }\r
104 \r
105     /**\r
106      * Check whether presetList is set in the command line\r
107      * \r
108      * @param cmd\r
109      *            command line options\r
110      * @return true if presetList is found, false otherwise\r
111      */\r
112     boolean listPresets(String[] cmd) {\r
113         return keyFound(cmd, presetList);\r
114     }\r
115 \r
116     /**\r
117      * Returns {@code Preset} by its name\r
118      * \r
119      * @see Preset\r
120      * @param <T>\r
121      * @param msaws\r
122      * @param presetName\r
123      * @return Return a Preset by its optionName\r
124      */\r
125     <T> Preset<T> getPreset(MsaWS<T> msaws, String presetName) {\r
126         assert presetName != null;\r
127         PresetManager<T> presets = getPresetList(msaws);\r
128         if (presets == null) {\r
129             System.out\r
130                     .println("No presets are supported by the service! Ignoring -r directive!");\r
131             return null;\r
132         }\r
133         Preset<T> pre = presets.getPresetByName(presetName);\r
134         if (pre == null) {\r
135             System.out.println("Cannot find preset: " + presetName\r
136                     + " WARN: ignoring -r directive!");\r
137         }\r
138         return pre;\r
139     }\r
140 \r
141     /**\r
142      * Extracts preset name from the command line is any\r
143      * \r
144      * @param cmd\r
145      *            command line options\r
146      * @return presetName or null if no presets is defined\r
147      */\r
148     String getPresetName(String[] cmd) {\r
149         String preset = null;\r
150         for (int i = 0; i < cmd.length; i++) {\r
151             String presetPrm = cmd[i];\r
152             if (presetPrm.trim().toLowerCase().startsWith(\r
153                     presetkey + pseparator)) {\r
154                 preset = presetPrm.substring(presetPrm.indexOf(pseparator) + 1);\r
155                 break;\r
156             }\r
157         }\r
158         return preset;\r
159     }\r
160 \r
161     /**\r
162      * Checks whether limitList parameter is in the command line\r
163      * \r
164      * @param cmd\r
165      *            - command line options\r
166      * @return true if it is, false otherwise\r
167      */\r
168     boolean listLimits(String[] cmd) {\r
169         return keyFound(cmd, limitList);\r
170     }\r
171 \r
172     /**\r
173      * Checks whether the key is in the command line\r
174      * \r
175      * @param cmd\r
176      * @param key\r
177      * @return true if it is, false otherwise\r
178      */\r
179     boolean keyFound(String[] cmd, String key) {\r
180         assert cmd != null && cmd.length > 0;\r
181         assert key != null;\r
182         for (int i = 0; i < cmd.length; i++) {\r
183             String listPresets = cmd[i];\r
184             if (listPresets.trim().equalsIgnoreCase(key)) {\r
185                 return true;\r
186             }\r
187         }\r
188         return false;\r
189     }\r
190 \r
191     /**\r
192      * Attempt to construct the URL object from the string\r
193      * \r
194      * @param urlstr\r
195      * @return true if it succeed false otherwise\r
196      */\r
197     public static boolean validURL(String urlstr) {\r
198         try {\r
199             if (urlstr == null || urlstr.trim().length() == 0) {\r
200                 return false;\r
201             }\r
202             new URL(urlstr);\r
203         } catch (MalformedURLException e) {\r
204             return false;\r
205         }\r
206         return true;\r
207     }\r
208 \r
209     /**\r
210      * Extracts service name from the command line\r
211      * \r
212      * @param cmd\r
213      *            command line options\r
214      * @return service name or null if it is not defined\r
215      */\r
216     public static String getServiceName(String[] cmd) {\r
217         for (int i = 0; i < cmd.length; i++) {\r
218             String serv = cmd[i];\r
219             if (serv.trim().toLowerCase().startsWith(servicekey + pseparator)) {\r
220                 return serv.substring(serv.indexOf(pseparator) + 1);\r
221             }\r
222         }\r
223         return null;\r
224     }\r
225 \r
226     /**\r
227      * Extracts host name from the command line\r
228      * \r
229      * @param cmd\r
230      *            command line options\r
231      * @return host name or null if it is not defined\r
232      */\r
233     public static String getHost(String[] cmd) {\r
234         for (int i = 0; i < cmd.length; i++) {\r
235             String host = cmd[i];\r
236             if (host.trim().toLowerCase().startsWith(hostkey + pseparator)) {\r
237                 return host.substring(host.indexOf(pseparator) + 1);\r
238             }\r
239         }\r
240         return null;\r
241     }\r
242 \r
243     /**\r
244      * Checks -i options and return the File if one was provided, null otherwise\r
245      * \r
246      * @param cmd\r
247      * @param key\r
248      * @param mustExist\r
249      * @return\r
250      * @throws IOException\r
251      */\r
252     File getFile(String[] cmd, String key, boolean mustExist)\r
253             throws IOException {\r
254         assert key != null && key.trim().length() != 0;\r
255         for (int i = 0; i < cmd.length; i++) {\r
256             String filename = cmd[i];\r
257             filename = filename.trim();\r
258             if (filename.toLowerCase().startsWith(key + pseparator)) {\r
259                 filename = filename.substring((key + pseparator).length());\r
260                 File file = new File(filename);\r
261                 if (mustExist && !file.exists()) {\r
262                     System.out.println(key + " file " + file.getAbsolutePath()\r
263                             + " does not exist");\r
264                     return null;\r
265                 }\r
266                 if (!mustExist && !file.exists()) {\r
267                     file.createNewFile();\r
268                 }\r
269                 if (!file.canRead()) {\r
270                     System.out.println("Cannot read " + key + " file "\r
271                             + file.getAbsolutePath());\r
272                     return null;\r
273                 }\r
274                 return file;\r
275             }\r
276         }\r
277         return null;\r
278     }\r
279 \r
280     /**\r
281      * Connects to the service and do the job as requested, if something goes\r
282      * wrong reports or/and prints usage help.\r
283      * \r
284      * @param <T>\r
285      *            web service type\r
286      * @param cmd\r
287      *            command line options\r
288      * @throws IOException\r
289      */\r
290     <T> Jws2Client(String[] cmd) throws IOException {\r
291 \r
292         String hostname = getHost(cmd);\r
293         if (hostname == null) {\r
294             System.out.println("Host name is not provided!");\r
295             printUsage(1);\r
296         }\r
297 \r
298         if (!validURL(hostname)) {\r
299             System.out.println("Host name is not valid!");\r
300             printUsage(1);\r
301         }\r
302         String serviceName = getServiceName(cmd);\r
303         if (serviceName == null) {\r
304             System.out.println("Service name is no provided!");\r
305             printUsage(1);\r
306         }\r
307         Services service = Services.getService(serviceName);\r
308         if (service == null) {\r
309             System.out.println("Service " + serviceName\r
310                     + " is no supported! Valid values are: "\r
311                     + Arrays.toString(Services.values()));\r
312             printUsage(1);\r
313         }\r
314         File inputFile = getFile(cmd, inputkey, true);\r
315         File outFile = getFile(cmd, outputkey, false);\r
316         File parametersFile = getFile(cmd, paramFile, true);\r
317         String presetName = getPresetName(cmd);\r
318 \r
319         MsaWS<T> msaws = connect(hostname, service);\r
320         Preset<T> preset = null;\r
321         if (presetName != null) {\r
322             preset = getPreset(msaws, presetName);\r
323         }\r
324         List<Option<T>> customOptions = null;\r
325         if (parametersFile != null) {\r
326             List<String> prms = loadParameters(parametersFile);\r
327             customOptions = processParameters(prms, msaws.getRunnerOptions());\r
328         }\r
329         Alignment alignment = null;\r
330         if (inputFile != null) {\r
331             alignment = align(inputFile, msaws, preset, customOptions);\r
332             OutputStream outStream = null;\r
333             if (outFile != null) {\r
334                 outStream = getOutStream(outFile);\r
335             } else {\r
336                 // this stream is going to be closed later which is fine as\r
337                 // std.out will not be\r
338                 outStream = System.out;\r
339             }\r
340             writeOut(outStream, alignment);\r
341             // stream is closed in the method no need to close it here\r
342         }\r
343 \r
344         boolean listParameters = listParameters(cmd);\r
345         if (listParameters) {\r
346             System.out.println(getParametersList(msaws));\r
347         }\r
348         boolean listPreset = listPresets(cmd);\r
349         if (listPreset) {\r
350             System.out.println(getPresetList(msaws));\r
351         }\r
352         boolean listLimits = listLimits(cmd);\r
353         if (listLimits) {\r
354             System.out.println(getLimits(msaws));\r
355         }\r
356         log.fine("Disconnecting...");\r
357         ((Closeable) msaws).close();\r
358         log.fine("Disconnected successfully!");\r
359     }\r
360 \r
361     /**\r
362      * Load parameters from file\r
363      * \r
364      * @throws IOException\r
365      */\r
366     List<String> loadParameters(File paramsfile) throws IOException {\r
367         assert paramsfile != null && paramsfile.exists();\r
368         BufferedReader reader = new BufferedReader(new FileReader(paramsfile));\r
369         String line = null;\r
370         ArrayList<String> params = new ArrayList<String>();\r
371         while ((line = reader.readLine()) != null) {\r
372             line = line.trim();\r
373             if (line.length() == 0)\r
374                 continue;\r
375             params.add(line);\r
376         }\r
377         return params;\r
378     }\r
379 \r
380     /**\r
381      * Converts options supplied via parameters file into {@code Option} objects\r
382      * \r
383      * @param <T>\r
384      *            web service type\r
385      * @param params\r
386      * @param options\r
387      * @return List of Options of type T\r
388      */\r
389     <T> List<Option<T>> processParameters(List<String> params,\r
390             RunnerConfig<T> options) {\r
391         List<Option<T>> chosenOptions = new ArrayList<Option<T>>();\r
392         for (String param : params) {\r
393             String oname = null;\r
394             if (isParameter(param)) {\r
395                 oname = this.getParamName(param);\r
396             } else {\r
397                 oname = param;\r
398             }\r
399             Option<T> o = options.getArgumentByOptionName(oname);\r
400             if (o == null) {\r
401                 System.out.println("WARN ignoring unsuppoted parameter: "\r
402                         + oname);\r
403                 continue;\r
404             }\r
405             if (isParameter(param)) {\r
406                 try {\r
407                     o.setValue(getParamValue(param));\r
408                 } catch (WrongParameterException e) {\r
409                     System.out\r
410                             .println("Problem setting value for the parameter: "\r
411                                     + param);\r
412                     e.printStackTrace();\r
413                 }\r
414             }\r
415             chosenOptions.add(o);\r
416         }\r
417         return chosenOptions;\r
418     }\r
419 \r
420     String getParamName(String fullName) {\r
421         assert isParameter(fullName);\r
422         return fullName.substring(0, fullName.indexOf(pseparator));\r
423     }\r
424 \r
425     String getParamValue(String fullName) {\r
426         assert isParameter(fullName);\r
427         return fullName.substring(fullName.indexOf(pseparator) + 1);\r
428     }\r
429 \r
430     boolean isParameter(String param) {\r
431         return param.contains(pseparator);\r
432     }\r
433 \r
434     OutputStream getOutStream(File file) {\r
435         assert file != null && file.exists();\r
436         try {\r
437             return new FileOutputStream(file);\r
438         } catch (FileNotFoundException e) {\r
439             e.printStackTrace();\r
440         }\r
441         return null;\r
442     }\r
443 \r
444     /**\r
445      * Outputs clustal formatted alignment into the file represented by the\r
446      * outStream\r
447      * \r
448      * @param outStream\r
449      * @param align\r
450      *            the alignment to output\r
451      */\r
452     void writeOut(OutputStream outStream, Alignment align) {\r
453         try {\r
454             ClustalAlignmentUtil.writeClustalAlignment(outStream, align);\r
455         } catch (IOException e) {\r
456             System.err\r
457                     .println("Problems writing output file! Stack trace is below: ");\r
458             e.printStackTrace();\r
459         } finally {\r
460             if (outStream != null) {\r
461                 try {\r
462                     outStream.close();\r
463                 } catch (IOException ignored) {\r
464                     // e.printStackTrace();\r
465                 }\r
466             }\r
467         }\r
468     }\r
469 \r
470     /**\r
471      * Connects to a web service by the host and the service name\r
472      * \r
473      * @param <T>\r
474      *            web service type\r
475      * @param host\r
476      * @param service\r
477      * @return MsaWS<T>\r
478      * @throws WebServiceException\r
479      */\r
480     public static <T> MsaWS<T> connect(String host, Services service)\r
481             throws WebServiceException {\r
482         URL url = null;\r
483         log.log(Level.FINE, "Attempt to connect...");\r
484         try {\r
485             url = new URL(host + "/" + service.toString() + "?wsdl");\r
486         } catch (MalformedURLException e) {\r
487             e.printStackTrace();\r
488             // ignore as the host name is already verified\r
489         }\r
490         QName qname = new QName(qualifiedServiceName, service.toString());\r
491         Service serv = Service.create(url, qname);\r
492         MsaWS<T> msaws = serv.getPort(new QName(qualifiedServiceName, service\r
493                 + "Port"), MsaWS.class);\r
494         log.log(Level.FINE, "Connected successfully!");\r
495         return msaws;\r
496     }\r
497 \r
498     /**\r
499      * Align sequences from the file using MsaWS\r
500      * \r
501      * @param <T>\r
502      *            web service type e.g. Clustal\r
503      * @param file\r
504      *            to write the resulting alignment to\r
505      * @param msaws\r
506      *            MsaWS required\r
507      * @param preset\r
508      *            Preset to use optional\r
509      * @param customOptions\r
510      *            file which contains new line separated list of options\r
511      * @return Alignment\r
512      */\r
513     static <T> Alignment align(File file, MsaWS<T> msaws, Preset<T> preset,\r
514             List<Option<T>> customOptions) {\r
515         FileInputStream instream = null;\r
516         List<FastaSequence> fastalist = null;\r
517         Alignment alignment = null;\r
518         try {\r
519             instream = new FileInputStream(file);\r
520             fastalist = SequenceUtil.readFasta(instream);\r
521             instream.close();\r
522             String jobId = null;\r
523             if (customOptions != null && preset != null) {\r
524                 System.out\r
525                         .println("WARN: Parameters (-f) are defined together with a preset (-r) ignoring preset!");\r
526             }\r
527             if (customOptions != null) {\r
528                 jobId = msaws.customAlign(fastalist, customOptions);\r
529             } else if (preset != null) {\r
530                 jobId = msaws.presetAlign(fastalist, preset);\r
531             } else {\r
532                 jobId = msaws.align(fastalist);\r
533             }\r
534             Thread.sleep(1000);\r
535             alignment = msaws.getResult(jobId);\r
536 \r
537         } catch (IOException e) {\r
538             System.err\r
539                     .println("Exception while reading the input file. "\r
540                             + "Check that the input file contains a list of fasta formatted sequences! "\r
541                             + "Exception details are below:");\r
542             e.printStackTrace();\r
543         } catch (JobSubmissionException e) {\r
544             System.err\r
545                     .println("Exception while submitting job to a web server. "\r
546                             + "Exception details are below:");\r
547             e.printStackTrace();\r
548         } catch (ResultNotAvailableException e) {\r
549             System.err.println("Exception while waiting for results. "\r
550                     + "Exception details are below:");\r
551             e.printStackTrace();\r
552         } catch (InterruptedException ignored) {\r
553             // ignore and propagate an interruption\r
554             Thread.currentThread().interrupt();\r
555         } catch (WrongParameterException e) {\r
556             e.printStackTrace();\r
557         } finally {\r
558             if (instream != null) {\r
559                 try {\r
560                     instream.close();\r
561                 } catch (IOException ignored) {\r
562                     // ignore\r
563                 }\r
564             }\r
565         }\r
566         return alignment;\r
567     }\r
568 \r
569     /**\r
570      * Returns a list of options supported by web service\r
571      * \r
572      * @param <T>\r
573      *            web service type\r
574      * @param msaws\r
575      *            web service proxy\r
576      * @return List of options supported by a web service\r
577      */\r
578     <T> List<Option<T>> getParametersList(MsaWS<T> msaws) {\r
579         assert msaws != null;\r
580         return msaws.getRunnerOptions().getArguments();\r
581     }\r
582 \r
583     /**\r
584      * Returns an objects from which the list of presets supported by web\r
585      * service <T> can be obtained\r
586      * \r
587      * @param <T>\r
588      *            web service type\r
589      * @param msaws\r
590      *            web service proxy\r
591      * @return PresetManager, object which operates on presets\r
592      */\r
593     <T> PresetManager<T> getPresetList(MsaWS<T> msaws) {\r
594         assert msaws != null;\r
595         PresetManager<T> presetman = msaws.getPresets();\r
596         return presetman;\r
597     }\r
598 \r
599     /**\r
600      * Returns a list of limits supported by web service Each limit correspond\r
601      * to a particular preset.\r
602      * \r
603      * @param <T>\r
604      *            web service type\r
605      * @param msaws\r
606      *            web service proxy\r
607      * @return List of limits supported by a web service\r
608      */\r
609     <T> List<Limit<T>> getLimits(MsaWS<T> msaws) {\r
610         assert msaws != null;\r
611         LimitsManager<T> lmanger = msaws.getLimits();\r
612 \r
613         return lmanger != null ? lmanger.getLimits() : null;\r
614     }\r
615 \r
616     /**\r
617      * Prints Jws2Client usage information to standard out\r
618      * \r
619      * @param exitStatus\r
620      */\r
621     static void printUsage(int exitStatus) {\r
622         System.out.println();\r
623         System.out.println("Usage: <Class or Jar file name> " + hostkey\r
624                 + pseparator + "host_and_context " + servicekey + pseparator\r
625                 + "serviceName ACTION [OPTIONS] ");\r
626         System.out.println();\r
627         System.out\r
628                 .println(hostkey\r
629                         + pseparator\r
630                         + "<host_and_context> - a full URL to the JWS2 web server including context path e.g. http://10.31.1.159:8080/ws");\r
631         System.out.println(servicekey + pseparator + "<ServiceName> - one of "\r
632                 + Arrays.toString(Services.values()));\r
633         System.out.println();\r
634         System.out.println("ACTIONS: ");\r
635         System.out\r
636                 .println(inputkey\r
637                         + pseparator\r
638                         + "<inputFile> - full path to fasta formatted sequence file, from which to align sequences");\r
639         System.out.println(paramList\r
640                 + " - lists parameters supported by web service");\r
641         System.out.println(presetList\r
642                 + " - lists presets supported by web service");\r
643         System.out.println(limitList + " - lists web services limits");\r
644         System.out\r
645                 .println("Please note that if input file is specified other actions are ignored");\r
646 \r
647         System.out.println();\r
648         System.out.println("OPTIONS (only for use with -i action):");\r
649 \r
650         System.out.println(presetkey + pseparator\r
651                 + "<presetName> - name of the preset to use");\r
652         System.out\r
653                 .println(outputkey\r
654                         + pseparator\r
655                         + "<outputFile> - full path to the file where to write an alignment");\r
656         System.out\r
657                 .println("-f=<parameterInputFile> - the name of the file with the list of parameters to use.");\r
658         System.out\r
659                 .println("Please note that -r and -f options cannot be used together. "\r
660                         + "Alignment is done with either preset or a parameters from the file, but not both!");\r
661 \r
662         System.exit(exitStatus);\r
663     }\r
664 \r
665     /**\r
666      * Starts command line client, if no parameter are supported print help. Two\r
667      * parameters are required for successfull call the JWS2 host name and a\r
668      * service name.\r
669      * \r
670      * @param args\r
671      *            Usage: <Class or Jar file name> -h=host_and_context\r
672      *            -s=serviceName ACTION [OPTIONS]\r
673      * \r
674      *            -h=<host_and_context> - a full URL to the JWS2 web server\r
675      *            including context path e.g. http://10.31.1.159:8080/ws\r
676      * \r
677      *            -s=<ServiceName> - one of [MafftWS, MuscleWS, ClustalWS,\r
678      *            TcoffeeWS, ProbconsWS] ACTIONS:\r
679      * \r
680      *            -i=<inputFile> - full path to fasta formatted sequence file,\r
681      *            from which to align sequences\r
682      * \r
683      *            -parameters - lists parameters supported by web service\r
684      * \r
685      *            -presets - lists presets supported by web service\r
686      * \r
687      *            -limits - lists web services limits Please note that if input\r
688      *            file is specified other actions are ignored\r
689      * \r
690      *            OPTIONS: (only for use with -i action):\r
691      * \r
692      *            -r=<presetName> - name of the preset to use\r
693      * \r
694      *            -o=<outputFile> - full path to the file where to write an\r
695      *            alignment -f=<parameterInputFile> - the name of the file with\r
696      *            the list of parameters to use. Please note that -r and -f\r
697      *            options cannot be used together. Alignment is done with either\r
698      *            preset or a parameters from the file, but not both!\r
699      * \r
700      */\r
701     public static void main(String[] args) {\r
702 \r
703         if (args == null) {\r
704             printUsage(1);\r
705         }\r
706         if (args.length < 2) {\r
707             System.out.println("Host and service names are required!");\r
708             printUsage(1);\r
709         }\r
710 \r
711         try {\r
712             new Jws2Client(args);\r
713         } catch (IOException e) {\r
714             log.log(Level.SEVERE, "IOException in client! " + e.getMessage(), e\r
715                     .getCause());\r
716             System.err.println("Cannot write output file! Stack trace: ");\r
717             e.printStackTrace();\r
718         }\r
719     }\r
720 }\r