1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package gov.nasa.pds.tools;
17
18 import gov.nasa.pds.tools.config.VToolConfigKeys;
19 import gov.nasa.pds.tools.dict.Dictionary;
20 import gov.nasa.pds.tools.dict.parser.DictionaryParser;
21 import gov.nasa.pds.tools.file.FileList;
22 import gov.nasa.pds.tools.file.FileListGenerator;
23 import gov.nasa.pds.tools.flags.ToolsFlags;
24 import gov.nasa.pds.tools.label.Label;
25 import gov.nasa.pds.tools.label.parser.LabelParser;
26 import gov.nasa.pds.tools.label.parser.LabelParserFactory;
27 import gov.nasa.pds.tools.label.validate.Status;
28 import gov.nasa.pds.tools.logging.ToolsLevel;
29 import gov.nasa.pds.tools.logging.ToolsLogFormatter;
30 import gov.nasa.pds.tools.logging.ToolsLogRecord;
31 import gov.nasa.pds.tools.status.ExitStatus;
32 import gov.nasa.pds.tools.time.ToolsTime;
33 import gov.nasa.pds.tools.xsl.StyleSheet;
34
35 import java.io.ByteArrayInputStream;
36 import java.io.ByteArrayOutputStream;
37 import java.io.File;
38 import java.io.FileInputStream;
39 import java.io.FileNotFoundException;
40 import java.io.FileOutputStream;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.OutputStream;
44 import java.net.MalformedURLException;
45 import java.net.URL;
46 import java.text.SimpleDateFormat;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.Iterator;
50 import java.util.List;
51 import java.util.logging.FileHandler;
52 import java.util.logging.Handler;
53 import java.util.logging.Level;
54 import java.util.logging.Logger;
55 import java.util.logging.StreamHandler;
56
57 import javax.swing.text.BadLocationException;
58 import javax.xml.transform.Result;
59 import javax.xml.transform.Source;
60 import javax.xml.transform.Transformer;
61 import javax.xml.transform.TransformerException;
62 import javax.xml.transform.TransformerFactory;
63 import javax.xml.transform.stream.StreamResult;
64 import javax.xml.transform.stream.StreamSource;
65
66 import org.apache.commons.cli.CommandLine;
67 import org.apache.commons.cli.CommandLineParser;
68 import org.apache.commons.cli.GnuParser;
69 import org.apache.commons.cli.HelpFormatter;
70 import org.apache.commons.cli.MissingOptionException;
71 import org.apache.commons.cli.OptionBuilder;
72 import org.apache.commons.cli.Options;
73 import org.apache.commons.cli.ParseException;
74 import org.apache.commons.cli.UnrecognizedOptionException;
75 import org.apache.commons.configuration.AbstractConfiguration;
76 import org.apache.commons.configuration.Configuration;
77 import org.apache.commons.configuration.ConfigurationException;
78 import org.apache.commons.configuration.ConversionException;
79 import org.apache.commons.configuration.PropertiesConfiguration;
80 import org.apache.commons.io.FilenameUtils;
81
82 /***
83 * Class to perform automated validation to determine if a given data product
84 * is PDS compliant.
85 * <p>
86 * This replaces LVTool functionality.
87 *
88 * @author mcayanan
89 * @version $Revision: 2666 $
90 *
91 *
92 */
93 public class VTool implements VToolConfigKeys, ToolsFlags, ExitStatus,
94 Status, StyleSheet {
95 private final String VERSION_ID = "1.0.0";
96 private final String FILE_REP = "*";
97 private final String FRAG_EXT = "FMT";
98
99 private static Logger log = Logger.getLogger(VTool.class.getName());
100 private ByteArrayOutputStream byteStream;
101 private String currDir;
102 private boolean dictPassed;
103
104 private List logHandlers;
105 private Options options;
106 private CommandLineParser parser;
107 private CommandLine cmd;
108
109
110
111 private boolean alias;
112 private URL config;
113
114 private List dictionaries;
115 private List noFiles;
116 private List noDirs;
117 private boolean followPtrs;
118 private List includePaths;
119 private boolean force;
120 private boolean progress;
121 private List regexp;
122 private boolean recursive;
123 private List targets;
124 private File logFile;
125 private boolean showLog;
126 private File rptFile;
127 private String rptStyle;
128 private short verbose;
129 private String severity;
130
131 private int goodLbls;
132 private int badLbls;
133 private int unkLbls;
134
135 /***
136 * Default constructor.
137 */
138 public VTool() {
139 alias = false;
140 config = null;
141 dictionaries = null;
142
143 dictPassed = true;
144 noFiles = null;
145 noDirs = null;
146 followPtrs = true;
147 targets = null;
148 includePaths = null;
149 force = false;
150 progress = false;
151 regexp = null;
152 recursive = true;
153 rptFile = null;
154 rptStyle = "full";
155 severity = "Warning";
156 logFile = null;
157 showLog = false;
158 verbose = 2;
159
160 currDir = null;
161 options = new Options();
162 parser = new GnuParser();
163 logHandlers = new ArrayList();
164
165 goodLbls = 0;
166 badLbls = 0;
167 unkLbls = 0;
168 }
169
170 /***
171 * Show the version and disclaimer notice for VTool.
172 *
173 */
174 public void showVersion() {
175 System.out.println("\nPDS Validation Tool (VTool) " + VERSION_ID);
176 System.out.println("\nCopyright 2006-2007, by the California Institute of Technology. ALL\n"
177 + "RIGHTS RESERVED. United States Government Sponsorship acknowledged.\n"
178 + "Any commercial use must be negotiated with the Office of Technology\n"
179 + "Transfer at the California Institute of Technology. This software\n"
180 + "may be subject to U.S. export control laws. By accepting this\n"
181 + "software, the user agrees to comply with all applicable U.S. export\n"
182 + "laws and regulations. User has the responsibility to obtain export\n"
183 + "licenses, or other export authority as may be required before\n"
184 + "exporting such information to foreign countries or providing access\n"
185 + "to foreign persons.");
186 System.exit(GOODRUN);
187 }
188
189 /***
190 * Display VTool usage and help information
191 *
192 */
193 public void showHelp() {
194 HelpFormatter formatter = new HelpFormatter();
195 formatter.printHelp(37, "VTool", null, options, null);
196 System.exit(GOODRUN);
197 }
198
199 /***
200 * Builds the set of configurable parameters for VTool.
201 */
202 public void buildOpts() {
203 options.addOption(ALIAS[SHORT], ALIAS[LONG], false, "Enable aliasing");
204 options.addOption(FOLLOW[SHORT], FOLLOW[LONG], false,
205 "Do not follow or check for the existence of files referenced "
206 + "by pointer statements in a label");
207 options.addOption(HELP[SHORT], HELP[LONG], false, "Display usage");
208
209 options.addOption(PARTIAL[SHORT], PARTIAL[LONG], false,
210 "Force VTool to validate a label fragment");
211 options.addOption(LOCAL[SHORT], LOCAL[LONG], false,
212 "Validate files only in the target directory rather than "
213 + "recursively traversing down the subdirectories.");
214 options.addOption(PROGRESS[SHORT], PROGRESS[LONG], false,
215 "Enable progress reporting");
216 options.addOption(VERSION[SHORT], VERSION[LONG], false,
217 "Display VTool version");
218
219
220
221
222
223 OptionBuilder.withLongOpt(CONFIG[LONG]);
224 OptionBuilder.withDescription(
225 "Specify a configuration file to set the default values for VTool");
226 OptionBuilder.hasArg();
227 OptionBuilder.withArgName("file");
228 OptionBuilder.withType(String.class);
229 options.addOption(OptionBuilder.create(CONFIG[SHORT]));
230
231
232 OptionBuilder.withLongOpt(DICT[LONG]);
233 OptionBuilder.withDescription(
234 "Specify the Planetary Science Data Dictionary full file name/URL "
235 + "and any local dictionaries to include for validation. Separate "
236 + "each file name with a space");
237 OptionBuilder.hasArgs();
238 OptionBuilder.withArgName(".full files");
239 OptionBuilder.withValueSeparator(' ');
240 OptionBuilder.withType(String.class);
241 options.addOption(OptionBuilder.create(DICT[SHORT]));
242
243
244 OptionBuilder.withLongOpt(IGNOREFILE[LONG]);
245 OptionBuilder.withDescription(
246 "Specify file patterns to ignore from validation. Separate each "
247 + "with a space. Patterns should be surrounded by quotes "
248 + "(i.e. -X \"*TAB\" \"*IMG\" or -X \"*TAB *IMG\")");
249 OptionBuilder.hasArgs();
250 OptionBuilder.withArgName("patterns");
251 OptionBuilder.withValueSeparator(' ');
252 OptionBuilder.withType(String.class);
253 options.addOption(OptionBuilder.create(IGNOREFILE[SHORT]));
254
255
256
257 OptionBuilder.withLongOpt(TARGET[LONG]);
258 OptionBuilder.withDescription(
259 "Explicitly specify the targets (label files, URLs and directories) "
260 + "to validate. Targets can be specified implicitly as well. "
261 + "(example: VTool label.lbl)");
262 OptionBuilder.hasArgs();
263 OptionBuilder.withArgName("labels,URLs,dirs");
264 OptionBuilder.withType(String.class);
265 OptionBuilder.withValueSeparator(' ');
266 options.addOption(OptionBuilder.create(TARGET[SHORT]));
267
268
269 OptionBuilder.withLongOpt(REGEXP[LONG]);
270 OptionBuilder.withDescription(
271 "Specify file patterns to look for when validating a directory. "
272 + "Separate each with a space. Patterns should be surrounded by "
273 + "quotes (i.e. -e \"*.LBL\" \"*.FMT\" or -e \"*.LBL *.FMT\")");
274 OptionBuilder.hasArgs();
275 OptionBuilder.withArgName("patterns");
276 OptionBuilder.withValueSeparator(' ');
277 OptionBuilder.withType(String.class);
278 options.addOption(OptionBuilder.create(REGEXP[SHORT]));
279
280
281 OptionBuilder.withLongOpt(INCLUDES[LONG]);
282 OptionBuilder.withDescription(
283 "Specify the paths to look for files referenced by pointers in a "
284 + "label. Separate each with a space. Default is to always look "
285 + "at the same directory as the label");
286 OptionBuilder.hasArgs();
287 OptionBuilder.withArgName("paths");
288 OptionBuilder.withType(String.class);
289 OptionBuilder.withValueSeparator(' ');
290 options.addOption(OptionBuilder.create(INCLUDES[SHORT]));
291
292
293 OptionBuilder.withLongOpt(IGNOREDIR[LONG]);
294 OptionBuilder.withDescription(
295 "Specify directory patterns to ignore. Separate each with a space. "
296 + "Patterns should be surrounded by quotes "
297 + "(i.e. -D \"EXTRAS\" \"LABEL\" or -D \"EXTRAS LABEL\")");
298 OptionBuilder.hasArgs();
299 OptionBuilder.withArgName("patterns");
300 OptionBuilder.withValueSeparator(' ');
301 OptionBuilder.withType(String.class);
302 options.addOption(OptionBuilder.create(IGNOREDIR[SHORT]));
303
304
305 OptionBuilder.withLongOpt(LOG[LONG]);
306 OptionBuilder.withDescription(
307 "Specify the file name for the machine-readable log. A file "
308 + "specification is optional. If no file name is given, then "
309 + "the log will be written to standard out");
310 OptionBuilder.hasOptionalArg();
311 OptionBuilder.withArgName("file (optional)");
312 OptionBuilder.withType(String.class);
313 options.addOption(OptionBuilder.create(LOG[SHORT]));
314
315
316
317 OptionBuilder.withLongOpt(REPORT[LONG]);
318 OptionBuilder.withDescription(
319 "Specify the file name for the human-readable report. Default is "
320 + "to write to standard out if this flag is not specified. This "
321 + "report, however, will not print to standard out if this flag is "
322 + "missing AND the log file flag is specified with no file name");
323 OptionBuilder.hasArg();
324 OptionBuilder.withArgName("file");
325 OptionBuilder.withType(String.class);
326 options.addOption(OptionBuilder.create(REPORT[SHORT]));
327
328
329 OptionBuilder.withLongOpt(RPTSTYLE[LONG]);
330 OptionBuilder.withDescription(
331 "Specify the level of detail for the reporting. Valid values are "
332 + "'full' for a full view, 'min' for a minimal view and 'sum' for "
333 + "a summary view. Default is to see a full report if this flag is "
334 + "not specified");
335 OptionBuilder.hasArg();
336 OptionBuilder.withArgName("full|sum|min");
337 OptionBuilder.withType(String.class);
338 options.addOption(OptionBuilder.create(RPTSTYLE[SHORT]));
339
340
341 OptionBuilder.withLongOpt(VERBOSE[LONG]);
342 OptionBuilder.withDescription(
343 "Specify the severity level and above to include in the "
344 + "human-readable report: (1=Info, 2=Warning, 3=Error). "
345 + "Default is Warning and above (level 2)");
346 OptionBuilder.hasArg();
347 OptionBuilder.withArgName("1|2|3");
348 OptionBuilder.withType(short.class);
349 options.addOption(OptionBuilder.create(VERBOSE[SHORT]));
350
351 }
352
353 /***
354 * Parses the VTool command-line.
355 * @param argv arguments given on the command-line
356 */
357 public void parseLine(String[] argv) {
358 try {
359 cmd = parser.parse(options, argv);
360 }
361 catch( ParseException exp ) {
362 System.err.println(
363 "Command line parser failed.\n\nReason: "
364 + exp.getMessage() );
365 System.exit(TOOLFAILURE);
366 }
367 }
368
369 /***
370 * Queries the VTool command-line.
371 *
372 */
373 public void queryCmdLine() {
374 List targetList = new ArrayList();
375
376 try {
377
378 if (cmd.hasOption(HELP[SHORT]))
379 showHelp();
380
381
382 if (cmd.hasOption(VERSION[SHORT]))
383 showVersion();
384
385 if (cmd.hasOption(CONFIG[SHORT])) {
386 URL file = toURL(cmd.getOptionValue(CONFIG[SHORT]));
387 readConfigFile(file);
388 }
389
390
391 if (cmd.hasOption(LOG[SHORT])) {
392 if (cmd.getOptionValue(LOG[SHORT]) != null)
393 setLogFile(new File(cmd.getOptionValue(LOG[SHORT])));
394 else
395 setShowLog(true);
396 }
397
398 if (cmd.hasOption(VERBOSE[SHORT])) {
399 try {
400 setVerbose(Short.parseShort(cmd.getOptionValue(VERBOSE[SHORT])));
401 }
402 catch( NumberFormatException ne) {
403 throw new Exception("Problems parsing value for the 'v' flag: "
404 + cmd.getOptionValue(VERBOSE[SHORT]));
405 }
406 catch(IllegalArgumentException ae) {
407 throw new Exception(ae.getMessage());
408 }
409
410 }
411
412
413 if (cmd.getArgList().size() != 0)
414 targetList.addAll(cmd.getArgList());
415
416 if (cmd.hasOption(TARGET[SHORT])) {
417 targetList.addAll(
418 Arrays.asList(cmd.getOptionValues(TARGET[SHORT])));
419 }
420 setTargets(targetList);
421
422
423 if (cmd.hasOption(ALIAS[SHORT]))
424 setAlias(true);
425
426 if (cmd.hasOption(FOLLOW[SHORT]))
427 setFollowPtrs(false);
428
429
430 if (cmd.hasOption(INCLUDES[SHORT]))
431 setIncludePaths(
432 Arrays.asList(cmd.getOptionValues(INCLUDES[SHORT])));
433
434
435
436
437 if (cmd.hasOption(PROGRESS[SHORT]))
438 setProgress(true);
439
440 if (cmd.hasOption(LOCAL[SHORT]))
441 setRecursive(false);
442
443 if (cmd.hasOption(REGEXP[SHORT]))
444 setRegexp(Arrays.asList(cmd.getOptionValues(REGEXP[SHORT])));
445
446 if (cmd.hasOption(IGNOREFILE[SHORT])) {
447 setNoFiles(Arrays.asList(
448 cmd.getOptionValues(IGNOREFILE[SHORT])));
449 }
450
451 if (cmd.hasOption(IGNOREDIR[SHORT])) {
452 setNoDirs(Arrays.asList(cmd.getOptionValues(IGNOREDIR[SHORT])));
453 }
454
455 if (cmd.hasOption(DICT[SHORT]))
456 setDictionaries(Arrays.asList(cmd.getOptionValues(DICT[SHORT])));
457
458 if (cmd.hasOption(RPTSTYLE[SHORT]))
459 setRptStyle(cmd.getOptionValue(RPTSTYLE[SHORT]));
460
461 if (cmd.hasOption(REPORT[SHORT]))
462 setRptFile(new File(cmd.getOptionValue(REPORT[SHORT])));
463
464 if (cmd.hasOption(PARTIAL[SHORT]))
465 setForcePartial(true);
466
467 }
468 catch(MissingOptionException moe) {
469 System.err.println(moe.getMessage());
470 System.exit(TOOLFAILURE);
471 }
472 catch(UnrecognizedOptionException uoe) {
473 System.err.println(uoe.getMessage());
474 System.exit(TOOLFAILURE);
475 }
476 catch(Exception e) {
477 System.err.println(e.getMessage());
478 System.exit(TOOLFAILURE);
479 }
480 }
481
482 /***
483 * Get aliasing flag.
484 * @return 'true' if aliasing is ON, 'false' otherwise
485 */
486 public boolean getAlias() {
487 return this.alias;
488 }
489
490 /***
491 * Set aliasing flag.
492 * @param a 'false' if aliasing should be turned off,
493 * 'true' otherwise
494 */
495 public void setAlias(boolean a) {
496 this.alias = a;
497 }
498
499 /***
500 * Get data object validation flag.
501 */
502
503
504
505
506
507 /***
508 * Set data object flag.
509 * @param d 'true' if data object validation is to be performed,
510 * 'false' otherwise
511 */
512
513
514
515
516
517 /***
518 * Get a list of dictionary files passed into VTool.
519 * @return a List object of dictionary file names
520 */
521 public List getDictionaries() {
522 return this.dictionaries;
523 }
524
525 /***
526 * Set the dictionary file names passed into VTool .
527 * @param d a List object of dictionary files
528 */
529 public void setDictionaries(List d) {
530 this.dictionaries = d;
531 }
532
533 /***
534 * Get flag status that determines whether to follow pointers found
535 * in a label.
536 * @return 'true' to follow, 'false' otherwise
537 */
538 public boolean getFollowPtrs() {
539 return this.followPtrs;
540 }
541
542 /***
543 * Set the flag that determines whether to follow pointers found in
544 * a label.
545 * @param f 'true' to follow, 'false' otherwise
546 */
547 public void setFollowPtrs(boolean f) {
548 this.followPtrs = f;
549 }
550
551 /***
552 * Get flag status that determines whether standalone label fragment
553 * validation is enabled.
554 * @return 'true' to enable, 'false' otherwise
555 */
556 public boolean getForcePartial() {
557 return this.force;
558 }
559
560 /***
561 * Set the flag that determines whether to validate standalone label.
562 * fragments
563 * @param f 'true' to enable, 'false' otherwise
564 */
565 public void setForcePartial(boolean f) {
566 this.force = f;
567 }
568
569 /***
570 * Get the paths to search for files referenced by pointers in a label.
571 * @return Start paths
572 */
573 public List getIncludePaths() {
574 return this.includePaths;
575 }
576
577 /***
578 * Set the paths to search for files referenced by pointers.
579 * <p>
580 * Default is to always look first in the same directory
581 * as the label, then search specified directories.
582 * @param i List of paths
583 */
584 public void setIncludePaths(List i) {
585 this.includePaths = i;
586 }
587
588 /***
589 * Get the file name that contains the list of directories and/or
590 * directory patterns to ignore during validation.
591 * @return a list of directory names/patterns to exclude from validation
592 */
593 public List getNoDirs() {
594 return this.noDirs;
595 }
596
597 /***
598 * Set the flag to ignore specified directories.
599 * @param f a text file containing a list of directories and/or directory
600 * patterns to ignore during validation. The names must be listed one
601 * name per line.
602 */
603 public void setNoDirs(List f) {
604 this.noDirs = f;
605 }
606
607 /***
608 * Get the file name that contains the list of files and/or file patterns.
609 * to ignore during validation
610 * @return a list of files/file patterns to exclude from validation
611 */
612 public List getNoFiles() {
613 return this.noFiles;
614 }
615
616 /***
617 * Set the flag to ignore specified files.
618 * @param f a list of files/file patterns to ignore during validation.
619 */
620 public void setNoFiles(List f) {
621 this.noFiles = f;
622 }
623
624 /***
625 * Get the machine-readable log file name.
626 * @return log file
627 */
628 public File getLogFile() {
629 return this.logFile;
630 }
631
632 /***
633 * Set the file name for the machine-readable log.
634 * @param f file name of the log
635 */
636 public void setLogFile(File f) {
637 this.logFile = f;
638 }
639
640 /***
641 * Get the flag that determines whether to write the log to standard out.
642 * @return 'true' to show log, 'false' to not show log
643 */
644 public boolean getShowLog() {
645 return this.showLog;
646 }
647
648 /***
649 * Set the flag to write the log to standard out.
650 * @param l
651 */
652 public void setShowLog(boolean l) {
653 this.showLog = l;
654 }
655
656 /***
657 * Get the report file name for the human-readable report.
658 * @return Report file name
659 */
660 public File getRptFile() {
661 return this.rptFile;
662 }
663
664 /***
665 * Set the file for the human-readable report.
666 * @param f file name
667 */
668 public void setRptFile(File f) {
669 this.rptFile = f;
670 }
671
672 /***
673 * Get the output style that was set for the validation report.
674 * @return 'full' for a full report, 'sum' for a summary report or
675 * 'min' for minimal detail
676 */
677 public String getRptStyle() {
678 return this.rptStyle;
679 }
680
681 /***
682 * Set the output style for the report.
683 * @param style 'sum' for a summary report, 'min' for a minimal report,
684 * and 'full' for a full report
685 */
686 public void setRptStyle(String style) {
687 if ( (style.equalsIgnoreCase("sum") == false) &&
688 (style.equalsIgnoreCase("min") == false) &&
689 (style.equalsIgnoreCase("full") == false) ) {
690 throw new IllegalArgumentException(
691 "Invalid value entered for 's' flag. Value can only "
692 + "be either 'full', 'sum', or 'min'");
693 }
694 this.rptStyle = style;
695 }
696
697 /***
698 * Get the progress reporting flag.
699 * @return 'true' if progress reporting is enabled, 'false' otherwise
700 */
701
702 public boolean getProgress() {
703 return this.progress;
704 }
705
706 /***
707 * Set the progress reporting flag.
708 * @param p
709 */
710 public void setProgress(boolean p) {
711 this.progress = p;
712 }
713
714 /***
715 * Get the patterns to be matched when searching for files to validate in
716 * a directory.
717 * @return a List object of patterns
718 */
719 public List getRegexp() {
720 return this.regexp;
721 }
722
723 /***
724 * Set the patterns flag.
725 * @param e a List of patterns to be matched when searching for files to
726 * validate in a directory
727 */
728 public void setRegexp(List e) {
729 this.regexp = e;
730 }
731
732 /***
733 * Set the recursive flag.
734 * @param r 'true' to recursively traverse down a directory and all its
735 * sub-directories, 'false' otherwise
736 */
737 public void setRecursive(boolean r) {
738 this.recursive = r;
739 }
740
741 /***
742 * Get the list of targets
743 * @return a List object of files, URLs, and/or directories
744 */
745 public List getTargets() {
746 return this.targets;
747 }
748
749 /***
750 * Set the targets flag.
751 * @param t a List of files, URLs, and/or directories to be validated
752 */
753 public void setTargets(List t) {
754 this.targets = t;
755 }
756
757 /***
758 * Get the verbosity level.
759 * @return an integer value where '1' for info, '2' for warnings'
760 * and '3' for errors
761 */
762 public short getVerbose() {
763 return this.verbose;
764 }
765
766 /***
767 * Set the verbosity level and above to include in the reporting.
768 * @param v '1' for info, '2' for warnings, and '3' for errors
769 */
770 public void setVerbose(short v) {
771 if (v < 1 || v > 3) {
772 throw new IllegalArgumentException(
773 "Invalid value entered for 'v' flag. "
774 + "Valid values can only be 1, 2, or 3");
775 }
776 verbose = v;
777
778 if (verbose == 1)
779 severity = new String("Info");
780 else if (verbose == 2)
781 severity = new String("Warning");
782 else if (verbose == 3)
783 severity = new String("Error");
784 }
785
786 /***
787 * Reads a configuration file to set the default behaviors for VTool.
788 * <p>
789 * Flags set on the command-line will override flags set in the
790 * configuration file
791 *
792 * @param file a file containing keyword/value statements
793 */
794 public void readConfigFile(URL file) {
795 Configuration config = null;
796 AbstractConfiguration.setDelimiter(' ');
797
798 try {
799 config = new PropertiesConfiguration(file);
800 }
801 catch (ConfigurationException ce) {
802 System.err.println(ce.getMessage());
803 System.exit(TOOLFAILURE);
804 }
805
806 try {
807 if (config.isEmpty())
808 throw new Exception("Configuration file is empty: "
809 + file.toString());
810 if (config.containsKey(ALIASKEY))
811 setAlias(config.getBoolean(ALIASKEY));
812
813
814
815 if (config.containsKey(DICTKEY))
816 setDictionaries(config.getList(DICTKEY));
817 if (config.containsKey(FORCEKEY))
818 setForcePartial(config.getBoolean(FORCEKEY));
819 if (config.containsKey(FOLLOWKEY))
820 setFollowPtrs(config.getBoolean(FOLLOWKEY));
821 if (config.containsKey(IGNOREDIRKEY)) {
822 setNoDirs(config.getList(IGNOREDIRKEY));
823
824 for(int i=0; i < this.noDirs.size(); i++) {
825 this.noDirs.set(i,
826 this.noDirs.get(i).toString().replace('"', ' ').trim());
827 }
828 }
829 if (config.containsKey(IGNOREFILEKEY)) {
830 setNoFiles(config.getList(IGNOREFILEKEY));
831
832 for(int i=0; i < noFiles.size(); i++) {
833 this.noFiles.set(i,
834 this.noFiles.get(i).toString().replace('"', ' ').trim());
835 }
836 }
837 if (config.containsKey(INCLUDESKEY))
838 setIncludePaths(config.getList(INCLUDESKEY));
839 if (config.containsKey(LOGKEY)) {
840 String logValue = new String(config.getProperty(LOGKEY).toString());
841
842 if(logValue.equalsIgnoreCase("true")
843 || logValue.equalsIgnoreCase("false")) {
844 setShowLog(Boolean.valueOf(logValue).booleanValue());
845 }
846 else
847 setLogFile(new File(logValue));
848 }
849 if (config.containsKey(PROGRESSKEY))
850 setProgress(config.getBoolean(PROGRESSKEY));
851 if (config.containsKey(RECURSEKEY))
852 setRecursive(config.getBoolean(RECURSEKEY));
853 if (config.containsKey(REGEXPKEY)) {
854 setRegexp(config.getList(REGEXPKEY));
855
856 for(int i=0; i < this.regexp.size(); i++) {
857 this.regexp.set(i,
858 this.regexp.get(i).toString().replace('"', ' ').trim());
859 }
860 }
861 if (config.containsKey(REPORTKEY))
862 setRptFile(new File(config.getString(REPORTKEY)));
863 if (config.containsKey(STYLEKEY))
864 setRptStyle(config.getString(STYLEKEY));
865 if (config.containsKey(TARGETKEY))
866 setTargets(config.getList(TARGETKEY));
867 if (config.containsKey(VERBOSEKEY))
868 setVerbose(config.getShort(VERBOSEKEY));
869 } catch(ConversionException ce) {
870 System.err.println(ce.getMessage());
871 System.exit(TOOLFAILURE);
872 } catch(Exception ex) {
873 System.err.println(ex.getMessage());
874 System.exit(TOOLFAILURE);
875 }
876 }
877
878 /***
879 * Logs report header information such as version of the tool,
880 * execution time, and flag settings.
881 *
882 */
883 public void logRptHeader() {
884 ToolsTime time = new ToolsTime();
885
886
887 log.log(new ToolsLogRecord(Level.CONFIG,
888 "VTool Version " + VERSION_ID));
889 try {
890 log.log(new ToolsLogRecord(Level.CONFIG,
891 "Execution Date "
892 + time.getTime(new SimpleDateFormat("EEE, MMM dd yyyy 'at' HH:mm:ss a"))));
893 } catch(IllegalArgumentException eX) {
894 System.out.println(eX.getMessage());
895 System.exit(TOOLFAILURE);
896 }
897
898 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
899 "Target(s) " + targets));
900 if (dictionaries != null) {
901 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
902 "Dictionary File(s) " + dictionaries));
903 }
904
905 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
906 "Aliasing " + alias));
907 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
908 "Directory Recursion " + recursive));
909 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
910 "Follow Pointers " + followPtrs));
911 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
912 "Validate Standalone Fragments " + force));
913
914 if (logFile != null) {
915 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
916 "Log File " + logFile));
917 }
918 if (rptFile != null) {
919 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
920 "Report File " + rptFile));
921 }
922 if (rptStyle != null) {
923 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
924 "Report Style " + rptStyle));
925 }
926 if (severity != null) {
927 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
928 "Severity Level " + severity));
929 }
930 if (includePaths != null) {
931 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
932 "Include Path(s) " + includePaths));
933 }
934 if (config != null) {
935 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
936 "Configuration File " + config));
937 }
938 if (regexp != null) {
939 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
940 "Files Patterns " + regexp));
941 }
942 if (noDirs != null) {
943 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
944 "Excluded Directories " + noDirs));
945 }
946 if (noFiles != null) {
947 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
948 "Excluded Files " + noFiles));
949 }
950 log.log(new ToolsLogRecord(ToolsLevel.PARAMETER,
951 "Progress Reporting " + progress));
952 }
953
954 /***
955 * Configures the logger appropriately.
956 * <p>
957 * If a log file was specified on the command-line, the log
958 * will be written to that file. If the log flag was
959 * specified with no file spec, then the log will be written
960 * to standard out. Otherwise, the log will be written to
961 * memory (ByteArrayOutputStream).
962 *
963 */
964 public void setupLogger() {
965 Logger logger = Logger.getLogger("");
966 logger.setLevel(Level.ALL);
967
968 Handler []handler = logger.getHandlers();
969 for(int i = 0; i < logger.getHandlers().length; i++)
970 logger.removeHandler(handler[i]);
971
972
973
974 if(logFile != null) {
975 FileHandler file = setupFileHandler(logFile);
976 logger.addHandler(file);
977 logHandlers.add(file);
978 }
979
980 else if (showLog == true && rptFile == null) {
981 StreamHandler stream = setupStreamHandler(System.out);
982 logger.addHandler(stream);
983 logHandlers.add(stream);
984 }
985
986
987 else if (showLog == true && rptFile != null) {
988 byteStream = new ByteArrayOutputStream();
989 StreamHandler byteArray = setupStreamHandler(byteStream);
990 logger.addHandler(byteArray);
991 logHandlers.add(byteArray);
992
993 StreamHandler stream = setupStreamHandler(System.out);
994 logger.addHandler(stream);
995 logHandlers.add(stream);
996 }
997
998 else {
999 byteStream = new ByteArrayOutputStream();
1000 StreamHandler byteArray = setupStreamHandler(byteStream);
1001 logger.addHandler(byteArray);
1002 logHandlers.add(byteArray);
1003 }
1004
1005 }
1006
1007 /***
1008 * Sets up a handler to an outputstream.
1009 * @param out An outputstream to write the logger to
1010 * @return a stream handler
1011 */
1012 private StreamHandler setupStreamHandler(OutputStream out) {
1013 StreamHandler stream = new StreamHandler(out, new ToolsLogFormatter());
1014 stream.setLevel(Level.ALL);
1015
1016 return stream;
1017 }
1018
1019 /***
1020 * Sets up a file handler.
1021 * @param log The name of the file to write the logger to
1022 * @return a file handler to the input file
1023 */
1024 private FileHandler setupFileHandler(File log) {
1025 FileHandler file = null;
1026 try {
1027 file = new FileHandler(log.toString(), false);
1028 file.setLevel(Level.ALL);
1029 file.setFormatter(new ToolsLogFormatter());
1030 } catch (SecurityException s) {
1031 System.err.println(s.getMessage());
1032 System.exit(TOOLFAILURE);
1033 } catch (IOException iEx) {
1034 System.err.println(iEx.getMessage());
1035 System.exit(TOOLFAILURE);
1036 }
1037 return file;
1038 }
1039
1040 /***
1041 * Convert a string to a URL.
1042 * @param s The string to convert
1043 * @return A URL of the input string
1044 */
1045 private URL toURL(String s) {
1046 URL url = null;
1047 try {
1048 url = new URL(s);
1049 } catch (MalformedURLException ex) {
1050 try {
1051 url = new File(s).toURI().toURL();
1052 } catch (MalformedURLException mEx) {
1053 System.err.println(mEx.getMessage());
1054 System.exit(TOOLFAILURE);
1055 }
1056 }
1057 return url;
1058 }
1059
1060 /***
1061 * Parse the dictionary files.
1062 *
1063 * @param dictionary a list of dictionary URLs
1064 * @return a Dictionary object that includes all the dictionary
1065 * information from all the dictionary files passed in.
1066 */
1067 public Dictionary readDictionaries(List dictionary) {
1068 Dictionary dict = null;
1069 URL dd = null;
1070 Iterator i = dictionary.iterator();
1071
1072 try {
1073
1074 dd = toURL(i.next().toString());
1075 dict = DictionaryParser.parse(dd, this.alias);
1076 log.log(new ToolsLogRecord(Level.CONFIG,
1077 "Dictionary version \n"
1078 + dict.getInformation(), dd.toString()));
1079
1080 if(dict.getStatus().equals(FAIL)) {
1081 log.log(new ToolsLogRecord(ToolsLevel.NOTIFICATION,
1082 dict.getStatus(), dd.toString()));
1083 }
1084
1085 while (i.hasNext()) {
1086 dd = toURL(i.next().toString());
1087 Dictionary mergeDict = DictionaryParser.parse(dd, alias);
1088 dict.merge( mergeDict, true );
1089 log.log(new ToolsLogRecord(Level.CONFIG,
1090 "Dictionary version \n"
1091 + mergeDict.getInformation(), dd.toString()));
1092
1093 if(mergeDict.getStatus().equals(FAIL)) {
1094 log.log(new ToolsLogRecord(ToolsLevel.NOTIFICATION,
1095 mergeDict.getStatus(), dd.toString()));
1096 }
1097 }
1098 } catch (MalformedURLException uex) {
1099 System.err.println(uex.getMessage());
1100 System.exit(TOOLFAILURE);
1101 } catch (IOException iex) {
1102 System.err.println(iex.getMessage());
1103 System.exit(TOOLFAILURE);
1104 } catch (gov.nasa.pds.tools.label.parser.ParseException pe) {
1105 log.log(new ToolsLogRecord(ToolsLevel.NOTIFICATION,
1106 "FAIL", dd.toString()));
1107 dictPassed = false;
1108 }
1109 return dict;
1110 }
1111
1112 /***
1113 * Sets up the include paths and flag to follow pointers in
1114 * the parser.
1115 * @param parser The label parser to set properties for
1116 */
1117 private void setParserProps(LabelParser parser) {
1118 URL path = null;
1119 if (includePaths != null) {
1120 for( Iterator i = includePaths.iterator(); i.hasNext(); ) {
1121 path = toURL(i.next().toString());
1122 checkURL(path);
1123 parser.addIncludePath(path);
1124 }
1125 }
1126
1127 if (followPtrs == false)
1128 parser.getProperties().setProperty("parser.pointers", "false");
1129 }
1130
1131 /***
1132 * Checks for the existence of a URL.
1133 * @param url the url to check
1134 */
1135 private void checkURL(URL url) {
1136 try {
1137 url.openStream();
1138 } catch (IOException i) {
1139 System.err.println(i.getMessage());
1140 System.exit(TOOLFAILURE);
1141 }
1142 }
1143
1144 /***
1145 * Validate labels found in the specified targets. If the target
1146 * is a directory, this method will validate all labels found within
1147 * the directory and its sub-directories. If recursion is turned OFF,
1148 * then sub-directories will not be looked into.
1149 *
1150 * @param targets a list of files, directories, and/or URLs
1151 * @param dict the dictionary file
1152 */
1153 public void validateLabels(List targets, Dictionary dict) {
1154
1155 for (Iterator i1 = targets.iterator(); i1.hasNext();) {
1156 FileList fileList = new FileList();
1157 fileList = processTarget(i1.next().toString(), recursive);
1158
1159 for (Iterator i2 = fileList.getFiles().iterator(); i2.hasNext();) {
1160 URL target = toURL(i2.next().toString());
1161 String result = validateLabel(target, dict);
1162 saveResults(result);
1163 }
1164
1165 if (!fileList.getDirs().isEmpty())
1166 validateLabels(fileList.getDirs(), dict);
1167 }
1168
1169 }
1170
1171 /***
1172 * Record the results of a label validation to determine the success
1173 * of the tool run.
1174 * @param result 'PASS' for a good label, 'FAIL' for a bad label, or
1175 * 'UNKNOWN' for a label that skipped validation
1176 */
1177 private void saveResults(String result) {
1178 if (PASS.equals(result))
1179 ++goodLbls;
1180 else if (FAIL.equals(result))
1181 ++badLbls;
1182 else
1183 ++unkLbls;
1184 }
1185
1186 /***
1187 * Returns an exit status code based on the validation results.
1188 *
1189 * @return '0' if files "passed" and a '1' if any of the following
1190 * occurs:<br>
1191 * <ul>
1192 * <li>one or more files failed validation</li>
1193 * <li>one or more files skipped validation and in addition,
1194 * no other files passed validation</li>
1195 * <li>dictionary validation failed</li>
1196 * </ul>
1197 */
1198 public int getExitStatus() {
1199 int status = 0;
1200
1201
1202 if (badLbls > 0)
1203 status = BADRUN;
1204
1205
1206
1207 else if (unkLbls > 0 && goodLbls == 0)
1208 status = BADRUN;
1209
1210 else if (dictPassed == false)
1211 status = BADRUN;
1212 else
1213 status = GOODRUN;
1214
1215 return status;
1216 }
1217
1218 /***
1219 * Processes a target.
1220 *
1221 * @param target The file or URL to process
1222 * @param getSubDirs 'True' to look for sub-directories, 'false' otherwise
1223 * @return A FileList object containing the sub-directories and files
1224 * found in the target, if any
1225 */
1226 public FileList processTarget(String target, boolean getSubDirs) {
1227 FileListGenerator fileGen = new FileListGenerator();
1228 FileList list = new FileList();
1229 fileGen.setFilters(regexp, noFiles, noDirs);
1230
1231 try {
1232 list = fileGen.visitTarget(target, getSubDirs);
1233 } catch (MalformedURLException uEx) {
1234 System.err.println(uEx.getMessage());
1235 System.exit(TOOLFAILURE);
1236 } catch (IOException iEx) {
1237 System.err.println(iEx.getMessage());
1238 System.exit(TOOLFAILURE);
1239 } catch (BadLocationException bEx) {
1240 System.err.println(bEx.getMessage());
1241 System.exit(TOOLFAILURE);
1242 } catch (NullPointerException nEx) {
1243 System.err.println(nEx.getMessage());
1244 System.exit(TOOLFAILURE);
1245 }
1246 return list;
1247 }
1248
1249 /***
1250 * Validate a label file.
1251 *
1252 * @param file The URL of the file to be validated
1253 * @param dict a Dictionary object needed for semantic validation. If null,
1254 * only syntactic validation will be performed.
1255 * @return 'PASS' if the label passed the PDS validation step,
1256 * 'FAIL' if the label failed the PDS validation step, or
1257 * 'UNKOWN' if the label skipped the PDS validation step
1258 */
1259
1260 public String validateLabel(URL file, Dictionary dict) {
1261 LabelParserFactory factory = LabelParserFactory.getInstance();
1262 LabelParser parser = factory.newLabelParser();
1263 Label label = null;
1264 setParserProps(parser);
1265
1266 if (progress)
1267 showProgress(file);
1268 try {
1269
1270
1271 if ( (FilenameUtils.getExtension(file.getFile()).equalsIgnoreCase(FRAG_EXT))
1272 && (force) ) {
1273 if (dict == null)
1274 label = parser.parsePartial(file);
1275 else
1276 label = parser.parsePartial(file, dict);
1277 }
1278 else {
1279 if (dict == null)
1280 label = parser.parse(file);
1281 else
1282 label = parser.parse(file, dict);
1283 }
1284 } catch (gov.nasa.pds.tools.label.parser.ParseException pEx) {
1285 log.log(new ToolsLogRecord(ToolsLevel.NOTIFICATION,
1286 "SKIP", file.toString()));
1287 return UNKNOWN;
1288 } catch (IOException iEx) {
1289 log.log(new ToolsLogRecord(ToolsLevel.NOTIFICATION,
1290 "SKIP", file.toString()));
1291 log.log(new ToolsLogRecord(ToolsLevel.WARNING,
1292 iEx.getMessage(), file.toString()));
1293 return UNKNOWN;
1294 }
1295 log.log(new ToolsLogRecord(ToolsLevel.NOTIFICATION,
1296 label.getStatus(), file.toString()));
1297
1298 return label.getStatus();
1299 }
1300
1301 /***
1302 * Prints out the current directory being validated and
1303 * represents each file being validated by an asterisk.
1304 * This is used when progress reporting is enabled.
1305 *
1306 * @param file The URL being validated
1307 */
1308 public void showProgress(URL file) {
1309 URL dir = null;
1310 try {
1311 dir = new URL(file.toString().
1312 substring(0, file.toString().lastIndexOf("/")));
1313 } catch (MalformedURLException uEx) {
1314 System.err.println(uEx.getMessage());
1315 System.exit(TOOLFAILURE);
1316 }
1317
1318 if (dir.toString().equals(currDir)) {
1319 System.err.print(FILE_REP);
1320 }
1321 else {
1322 currDir = new String(dir.toString());
1323 System.err.println("\nValidating file(s) in: " + currDir);
1324 System.err.print(FILE_REP);
1325 }
1326 }
1327
1328 /***
1329 * Transforms an XML log to a human-readable report.
1330 *
1331 * @param in inputstream of the XML log
1332 * @param xsl the stylesheet to use in creating the human-readable report
1333 * @param level the severity level to set for the report (info, warning, or error)
1334 * @param output The stream type for the final report
1335 * @throws TransformerException If there was an error during the transformation
1336 * of the log to the final report
1337 */
1338 private void generateReport(InputStream in, String xsl, String level,
1339 OutputStream output) throws TransformerException {
1340
1341 Source xmlSource = new StreamSource(in);
1342 Source xsltSource = new StreamSource(getClass().getResourceAsStream(xsl));
1343 Result result = new StreamResult(output);
1344 TransformerFactory factory = TransformerFactory.newInstance();
1345 Transformer transformer = factory.newTransformer(xsltSource);
1346
1347 transformer.setParameter("level", level);
1348 transformer.transform(xmlSource, result);
1349 }
1350
1351 /***
1352 * Creates a human-readable report.
1353 *
1354 * @param log Where the xml log is located. If null, then the xml log
1355 * will be read from memory.
1356 * @param report Where the human-readable report will be written to.
1357 * If null, then it goes to standard out.
1358 * @param level The severity level to include in the report. Can be
1359 * "INFO", "WARNING", or "ERROR".
1360 * @param style The reporting style to generate. Can be either "full",
1361 * "sum", or "min" for a full, summary, or minimal report, respectively.
1362 */
1363 public void doReporting(File log, File report, String level, String style) {
1364 String xsl = null;
1365 InputStream input = null;
1366 OutputStream output = null;
1367
1368 if ( (level.equalsIgnoreCase("info") == false)
1369 && (level.equalsIgnoreCase("warning") == false)
1370 && (level.equalsIgnoreCase("error") == false) ) {
1371 throw new IllegalArgumentException("Invalid severity level: "
1372 + level + ". Must be 'info', 'warning', or 'error'.");
1373 }
1374
1375 xsl = getXSL(style);
1376
1377 try {
1378 input = getRptInStream(log);
1379 output = getRptOutStream(report);
1380 } catch (FileNotFoundException ex) {
1381 System.err.println(ex.getMessage());
1382 System.exit(TOOLFAILURE);
1383 }
1384
1385 try {
1386 generateReport(input, xsl, level.toUpperCase(), output);
1387 } catch (TransformerException t) {
1388 System.err.println(t.getMessage());
1389 System.exit(TOOLFAILURE);
1390 }
1391
1392 if(report == null)
1393 System.out.println();
1394 }
1395
1396 /***
1397 * Gets the proper XSL stylesheet.
1398 *
1399 * @param style 'full' for a full XSL, 'sum' for a summary XSL, or 'min'
1400 * for a minimal XSL
1401 * @return The XSL stylesheet name
1402 */
1403 private String getXSL(String style) {
1404 if (style.equalsIgnoreCase("full"))
1405 return FULLXSL;
1406 else if (style.equalsIgnoreCase("sum"))
1407 return SUMXSL;
1408 else if (style.equalsIgnoreCase("min"))
1409 return MINXSL;
1410 else {
1411 throw new IllegalArgumentException("Invalid style specified: "
1412 + style + ". Must be 'full', 'sum' or 'min'");
1413 }
1414 }
1415
1416 /***
1417 * Returns the input stream of the XML log for the final report.
1418 *
1419 * @param file A file name. If null, then a ByteArrayInputStream is returned.
1420 *
1421 * @return The proper input stream
1422 * @throws FileNotFoundException
1423 */
1424 private InputStream getRptInStream(File file) throws FileNotFoundException {
1425 if(file != null)
1426 return new FileInputStream(file);
1427 else
1428 return new ByteArrayInputStream(byteStream.toByteArray());
1429 }
1430
1431 /***
1432 * Returns the appropriate output stream for the final report.
1433 * @param rpt The report file name. If null, then the standard out
1434 * stream is returned.
1435 *
1436 * @return The proper output stream
1437 * @throws FileNotFoundException
1438 */
1439 private OutputStream getRptOutStream(File rpt) throws FileNotFoundException {
1440 if(rpt != null)
1441 return new FileOutputStream(rpt);
1442 else
1443 return System.out;
1444 }
1445
1446 /***
1447 * Closes the handlers that were set for the logger.
1448 *
1449 */
1450 public void closehandle() {
1451 for(Iterator i=logHandlers.iterator(); i.hasNext();) {
1452 Handler handler = (Handler) i.next();
1453 handler.close();
1454 }
1455 }
1456 /***
1457 * Implementation to perform automated PDS validation.
1458 *
1459 * <p>
1460 * The main calls the following methods (in this order):
1461 * <p>
1462 * To setup the flags and parse the command-line options:
1463 * <ul>
1464 * <li>buildOpts</li>
1465 * <li>parseLine</li>
1466 * <li>queryCmdLine</li>
1467 * </ul>
1468 *
1469 * <p>
1470 * To setup the logger and log the report header information:
1471 * <ul>
1472 * <li>setupLogger</li>
1473 * <li>logRptHeader</li>
1474 * </ul>
1475 *
1476 * <p>
1477 * To perform validation:
1478 * <ul>
1479 * <li>readDictionaries (if the PSDD was passed in)</li>
1480 * <li>validateLabels</li>
1481 * </ul>
1482 *
1483 * <p>
1484 * To create the final report:
1485 * <ul>
1486 * <li>closehandle (to flush the buffers)</li>
1487 * <li>doReporting</li>
1488 * </ul>
1489 *
1490 * <p>
1491 * Reporting is not generated if the log flag was specified with
1492 * no file spec and the report file flag was not specified
1493 *
1494 * <p>
1495 * VTool returns an appropriate exit status based on validation results.
1496 * <br>
1497 * In general, the following is returned:
1498 * <ul>
1499 * <li>'0' upon "successful" validation</li>
1500 * <li>'1' upon a valiadation "failure"</li>
1501 * <li>'-1' upon application failure</li>
1502 * </ul>
1503 *
1504 * @param argv Arguments passed on the command-line
1505 */
1506 public static void main(String[] argv) {
1507 VTool vtool = new VTool();
1508 Dictionary dictionary = null;
1509
1510 if (argv.length == 0) {
1511 System.out.println("\nType 'VTool -h' for usage");
1512 System.exit(GOODRUN);
1513 }
1514
1515
1516 vtool.buildOpts();
1517
1518 vtool.parseLine(argv);
1519
1520 vtool.queryCmdLine();
1521
1522 vtool.setupLogger();
1523
1524 vtool.logRptHeader();
1525
1526 if (vtool.dictionaries != null) {
1527 dictionary = vtool.readDictionaries(vtool.dictionaries);
1528
1529
1530 if (vtool.dictPassed)
1531 vtool.validateLabels(vtool.targets, dictionary);
1532 }
1533 else
1534 vtool.validateLabels(vtool.targets, null);
1535
1536 vtool.closehandle();
1537
1538
1539 if(vtool.progress == true)
1540 System.err.println();
1541
1542
1543
1544 if( !(vtool.showLog && vtool.rptFile == null) ) {
1545 vtool.doReporting(vtool.logFile, vtool.rptFile, vtool.severity, vtool.rptStyle);
1546 }
1547
1548 System.exit(vtool.getExitStatus());
1549 }
1550 }