1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.objectweb.fractal.cecilia.adl;
25
26 import java.io.File;
27 import java.io.PrintStream;
28 import java.net.MalformedURLException;
29 import java.net.URL;
30 import java.net.URLClassLoader;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.HashMap;
34 import java.util.LinkedHashMap;
35 import java.util.LinkedHashSet;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39
40
41
42
43 public abstract class AbstractLauncher {
44
45 protected final CmdPathOption srcPathOpt = new CmdPathOption(
46 "S",
47 "src-path",
48 "the search path of ADL,IDL and implementation files (list of path separated by '"
49 + File.pathSeparator + "')",
50 "<path list>");
51
52 protected final CmdArgument outDirOpt = new CmdArgument(
53 "o",
54 "out-path",
55 "the path where generated files will be put",
56 "<output path>", ".", false);
57
58 protected final CmdFlag helpOpt = new CmdFlag("h", "help",
59 "Print this help and exit");
60
61 protected final Options options = new Options();
62 {
63 options.addOptions(helpOpt, srcPathOpt, outDirOpt);
64 }
65
66
67
68
69
70 protected ClassLoader getSourceClassLoader(final List<String> srcPath) {
71 final List<String> validatedPaths = new ArrayList<String>(srcPath.size());
72
73
74 for (final String path : srcPath) {
75 final File f = new File(path);
76 if (!f.exists()) {
77 System.out.println("Warning '" + f.getAbsolutePath()
78 + "' source path can't be found ");
79 } else if (!f.isDirectory()) {
80 System.out.println("Warning: \"" + path
81 + "\" is not a directory, path ignored.");
82 } else {
83 validatedPaths.add(path);
84 }
85 }
86
87
88 final URL[] urls = new URL[validatedPaths.size()];
89 for (int i = 0; i < urls.length; i++) {
90 final String path = validatedPaths.get(i);
91 final File f = new File(path);
92 try {
93 urls[i] = f.toURI().toURL();
94 } catch (final MalformedURLException e) {
95
96 throw new Error(e);
97 }
98 }
99
100 return new URLClassLoader(urls, getClass().getClassLoader());
101 }
102
103 protected ClassLoader getSourceClassLoader(final CommandLine cmdLine) {
104 List<String> srcPath = srcPathOpt.getPathValue(cmdLine);
105 if (srcPath == null) {
106 srcPath = new ArrayList<String>(1);
107 srcPath.add(".");
108 }
109
110 return getSourceClassLoader(srcPath);
111 }
112
113 protected static File newBuildDir(final File outDir, final String dirName)
114 throws InvalidCommandLineException {
115 final File d = new File(outDir, dirName);
116 checkDir(d);
117 return d;
118 }
119
120 protected static File newBuildDir(final String name)
121 throws InvalidCommandLineException {
122 final File d = new File(name);
123 checkDir(d);
124 return d;
125 }
126
127 protected static void checkDir(final File d)
128 throws InvalidCommandLineException {
129 if (d.exists() && !d.isDirectory())
130 throw new InvalidCommandLineException("Invalid build directory '"
131 + d.getAbsolutePath() + "' not a directory", 6);
132 }
133
134 protected static List<String> parsePathList(String paths) {
135 final List<String> l = new ArrayList<String>();
136 int index = paths.indexOf(File.pathSeparatorChar);
137 while (index != -1) {
138 l.add(paths.substring(0, index));
139 paths = paths.substring(index + 1);
140 index = paths.indexOf(File.pathSeparatorChar);
141 }
142 l.add(paths);
143 return l;
144 }
145
146 protected static Map<String, List<String>> argsToMap(final String... args)
147 throws InvalidCommandLineException {
148 final Map<String, List<String>> map = new LinkedHashMap<String, List<String>>();
149 List<String> nonOptList = null;
150
151 for (final String arg : args) {
152 if (arg.startsWith("-")) {
153
154 final String argName;
155 final String argValue;
156
157 final int startIndex;
158 if (arg.startsWith("--"))
159 startIndex = 2;
160 else
161 startIndex = 1;
162
163 final int index = arg.indexOf('=');
164 if (index == -1) {
165 argName = arg.substring(startIndex);
166 argValue = null;
167 } else {
168 if (index < startIndex + 1) {
169 throw new InvalidCommandLineException("Invalid option '" + arg
170 + "'", 1);
171 }
172 argName = arg.substring(startIndex, index);
173 argValue = arg.substring(index + 1);
174 }
175
176 List<String> l = map.get(argName);
177 if (l == null) {
178 l = new ArrayList<String>();
179 map.put(argName, l);
180 }
181 l.add(argValue);
182
183 } else {
184 if (nonOptList == null) {
185 nonOptList = new ArrayList<String>();
186 map.put(null, nonOptList);
187 }
188 nonOptList.add(arg);
189 }
190 }
191
192 return map;
193 }
194
195 protected abstract void printUsage(PrintStream ps);
196
197 protected void printHelp(final PrintStream ps) {
198 printUsage(ps);
199 ps.println();
200 ps.println("Available options are :");
201 int maxCol = 0;
202
203 for (final CmdOption opt : options.getOptions()) {
204 final int col = 2 + opt.getPrototype().length();
205 if (col > maxCol) maxCol = col;
206 }
207 for (final CmdOption opt : options.getOptions()) {
208 final StringBuffer sb = new StringBuffer(" ");
209 sb.append(opt.getPrototype());
210 while (sb.length() < maxCol)
211 sb.append(' ');
212 sb.append(" ").append(opt.getDescription());
213 ps.println(sb);
214 }
215 }
216
217
218
219
220
221
222
223
224 public static class InvalidCommandLineException extends Exception {
225
226 protected final int exitValue;
227
228
229
230
231
232 public InvalidCommandLineException(final String message, final int exitValue) {
233 super(message);
234 this.exitValue = exitValue;
235 }
236
237
238
239
240 public int getExitValue() {
241 return exitValue;
242 }
243 }
244
245
246 public static class Options {
247 protected final Set<CmdOption> optionSet = new LinkedHashSet<CmdOption>();
248 protected final Map<String, CmdOption> optionsByShortName = new HashMap<String, CmdOption>();
249 protected final Map<String, CmdOption> optionsByLongName = new HashMap<String, CmdOption>();
250 protected final Map<String, CmdProperties> optionsByPrefix = new HashMap<String, CmdProperties>();
251
252
253
254
255
256
257 public void addOption(final CmdOption option) {
258 if (option instanceof CmdProperties) {
259 final CmdOption prevOpt = optionsByPrefix.put(option.shortName,
260 (CmdProperties) option);
261 if (prevOpt != null || optionsByShortName.containsKey(option.shortName)) {
262 throw new IllegalArgumentException("short name '" + option.shortName
263 + "' already used");
264 }
265 } else {
266 if (option.shortName != null) {
267 final CmdOption prevOpt = optionsByShortName.put(option.shortName,
268 option);
269 if (prevOpt != null || optionsByPrefix.containsKey(option.shortName)) {
270 throw new IllegalArgumentException("short name '"
271 + option.shortName + "' already used");
272 }
273 }
274 if (option.longName != null) {
275 final CmdOption prevOpt = optionsByLongName.put(option.longName,
276 option);
277 if (prevOpt != null) {
278 throw new IllegalArgumentException("long name '" + option.longName
279 + "' already used");
280 }
281 }
282 }
283
284 optionSet.add(option);
285 }
286
287
288
289
290
291
292 public void addOptions(final CmdOption... options) {
293 for (final CmdOption option : options) {
294 addOption(option);
295 }
296 }
297
298
299 public Collection<CmdOption> getOptions() {
300 return optionSet;
301 }
302
303 CmdOption getByShortName(final String shortName) {
304 return optionsByShortName.get(shortName);
305 }
306
307 CmdOption getByLongName(final String longName) {
308 return optionsByLongName.get(longName);
309 }
310
311 CmdOption getByName(final String name) {
312 final String prefix = name.substring(0, 1);
313
314 CmdOption option = optionsByPrefix.get(prefix);
315 if (option != null) return option;
316
317 option = optionsByShortName.get(name);
318 if (option != null) return option;
319
320 return optionsByLongName.get(name);
321 }
322 }
323
324
325
326
327
328 public static class CommandLine {
329 protected final Options options;
330 protected final Map<CmdOption, Object> optionValues = new LinkedHashMap<CmdOption, Object>();
331 protected final List<String> arguments = new ArrayList<String>();
332
333
334
335
336
337
338
339
340
341
342
343 public static CommandLine parseArgs(final Options options,
344 final boolean allowUnknownOption, final String... args)
345 throws InvalidCommandLineException {
346 final CommandLine cmdLine = new CommandLine(options);
347
348 for (final String arg : args) {
349 if (arg.startsWith("-")) {
350
351 final String argName;
352 final String argValue;
353
354 boolean longName;
355 final int startIndex;
356 if (arg.startsWith("--")) {
357 startIndex = 2;
358 longName = true;
359 } else {
360 startIndex = 1;
361 longName = false;
362 }
363
364 final int index = arg.indexOf('=');
365 if (index == -1) {
366 argName = arg.substring(startIndex);
367 argValue = null;
368 } else {
369 if (index < startIndex + 1) {
370 throw new InvalidCommandLineException("Invalid option '" + arg
371 + "'", 1);
372 }
373 argName = arg.substring(startIndex, index);
374 argValue = arg.substring(index + 1);
375 }
376
377 final CmdOption opt;
378 if (longName)
379 opt = cmdLine.options.getByLongName(argName);
380 else
381 opt = cmdLine.options.getByName(argName);
382
383 if (opt == null) {
384 if (allowUnknownOption) {
385 cmdLine.arguments.add(arg);
386 } else {
387 throw new InvalidCommandLineException("Unknown option '"
388 + argName + "'", 1);
389 }
390 } else {
391 if (opt instanceof CmdFlag) {
392 if (argValue != null) {
393 throw new InvalidCommandLineException("Invalid option '"
394 + argName + "' do not accept value", 1);
395 }
396
397 ((CmdFlag) opt).setPresent(cmdLine);
398
399 } else if (opt instanceof CmdProperties) {
400 if (argValue == null) {
401 throw new InvalidCommandLineException("Invalid option '"
402 + argName + "' expects a value", 1);
403 }
404 ((CmdProperties) opt).setValue(cmdLine, argName.substring(1),
405 argValue);
406 } else {
407 if (argValue == null) {
408 throw new InvalidCommandLineException("Invalid option '"
409 + argName + "' expects a value", 1);
410 }
411 ((CmdArgument) opt).setValue(cmdLine, argValue);
412 }
413 }
414 } else {
415 cmdLine.arguments.add(arg);
416 }
417 }
418 return cmdLine;
419 }
420
421 protected CommandLine(final Options options) {
422 this.options = options;
423 }
424
425 protected Object setOptionValue(final CmdOption option, final Object value) {
426 return optionValues.put(option, value);
427 }
428
429
430 public List<String> getArguments() {
431 return arguments;
432 }
433
434
435
436
437
438
439 public boolean isOptionPresent(final CmdOption option) {
440 return optionValues.containsKey(option);
441 }
442
443 Object getOptionValue(final CmdOption option) {
444 return optionValues.get(option);
445 }
446 }
447
448
449
450
451 public abstract static class CmdOption {
452 protected final String shortName;
453 protected final String longName;
454 protected final String description;
455
456
457
458
459
460
461
462
463
464 public CmdOption(final String shortName, final String longName,
465 final String description) {
466 if (shortName == null && longName == null)
467 throw new IllegalArgumentException("Invalid option names");
468 if (shortName != null && shortName.length() > 1)
469 throw new IllegalArgumentException("Invalid shortName");
470 if (longName != null && longName.length() <= 1)
471 throw new IllegalArgumentException("Invalid longName");
472
473 this.shortName = shortName;
474 this.longName = longName;
475 this.description = description;
476 }
477
478
479 public String getPrototype() {
480 String desc;
481 if (shortName != null) {
482 desc = "-" + shortName;
483 if (longName != null) {
484 desc += ", --" + longName;
485 }
486 } else {
487 desc = "--" + longName;
488 }
489 return desc;
490 }
491
492
493 public String getShortName() {
494 return shortName;
495 }
496
497
498 public String getLongName() {
499 return longName;
500 }
501
502
503 public String getDescription() {
504 return description;
505 }
506
507
508
509
510
511
512 public boolean isPresent(final CommandLine commandLine) {
513 return commandLine.isOptionPresent(this);
514 }
515
516 @Override
517 public boolean equals(final Object obj) {
518 if (this == obj) return true;
519
520 if (!(obj instanceof CmdOption)) return false;
521
522 final CmdOption opt = (CmdOption) obj;
523 if (shortName == null) {
524 return opt.shortName == null && opt.longName.equals(longName);
525 } else {
526 return shortName.equals(opt.shortName);
527 }
528 }
529
530 @Override
531 public int hashCode() {
532 if (shortName == null)
533 return longName.hashCode();
534 else
535 return shortName.hashCode();
536 }
537 }
538
539
540
541
542 public static class CmdFlag extends CmdOption {
543
544
545 public CmdFlag(final String shortName, final String longName,
546 final String description) {
547 super(shortName, longName, description);
548 }
549
550 void setPresent(final CommandLine commandLine) {
551 commandLine.setOptionValue(this, "");
552 }
553 }
554
555
556
557
558 public static class CmdArgument extends CmdOption {
559 protected final String argDesc;
560 protected final String defaultValue;
561 protected final boolean allowMultiple;
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578 public CmdArgument(final String shortName, final String longName,
579 final String description, final String argDesc,
580 final String defaultValue, final boolean allowMultiple) {
581 super(shortName, longName, (defaultValue == null)
582 ? description
583 : description + " (default is '" + defaultValue + "')");
584 this.argDesc = argDesc;
585 this.defaultValue = defaultValue;
586 this.allowMultiple = allowMultiple;
587 }
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602 public CmdArgument(final String shortName, final String longName,
603 final String description, final String argDesc) {
604 this(shortName, longName, description, argDesc, null, false);
605 }
606
607 void setValue(final CommandLine commandLine, final String value)
608 throws InvalidCommandLineException {
609 if (value == null) return;
610 final Object prevValue = commandLine.setOptionValue(this, value);
611 if (!allowMultiple && prevValue != null) {
612 throw new InvalidCommandLineException("'" + longName
613 + "' can't be specified several times.", 1);
614 }
615 }
616
617
618
619
620
621
622
623
624
625
626 public String getValue(final CommandLine commandLine) {
627 final String optionValue = (String) commandLine.getOptionValue(this);
628 return optionValue == null ? defaultValue : optionValue;
629 }
630
631
632 public String getDefaultValue() {
633 return defaultValue;
634 }
635
636 @Override
637 public String getPrototype() {
638 String desc;
639 if (shortName != null) {
640 desc = "-" + shortName + "=" + argDesc;
641 if (longName != null) {
642 desc += ", --" + longName;
643 }
644 } else {
645 desc = "--" + longName + "=" + argDesc;
646 }
647 return desc;
648 }
649
650 @Override
651 public String getDescription() {
652 if (allowMultiple)
653 return super.getDescription()
654 + ". This option may be specified several times.";
655 else
656 return super.getDescription();
657 }
658 }
659
660
661
662
663 public static class CmdProperties extends CmdOption {
664 protected final String argNameDesc;
665 protected final String argValueDesc;
666
667
668
669
670
671
672
673
674
675
676
677 public CmdProperties(final String shortName, final String description,
678 final String argNameDesc, final String argValueDesc) {
679 super(shortName, null, description
680 + ". This option may be specified several times.");
681 this.argNameDesc = argNameDesc;
682 this.argValueDesc = argValueDesc;
683 }
684
685 @Override
686 public String getPrototype() {
687 return "-" + shortName + argNameDesc + "=" + argValueDesc;
688 }
689
690 @SuppressWarnings("unchecked")
691 void setValue(final CommandLine commandLine, final String name,
692 final String value) throws InvalidCommandLineException {
693 if (name == null || value == null) return;
694 Map<String, String> values = (Map<String, String>) commandLine
695 .getOptionValue(this);
696 if (values == null) {
697 values = new HashMap<String, String>();
698 commandLine.setOptionValue(this, values);
699 }
700 values.put(name, value);
701 }
702
703
704
705
706
707
708
709
710 @SuppressWarnings("unchecked")
711 public Map<String, String> getValue(final CommandLine commandLine) {
712 return (Map<String, String>) commandLine.getOptionValue(this);
713 }
714 }
715
716
717
718
719
720
721 public static class CmdAppendOption extends CmdArgument {
722
723 protected final String separator;
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738 public CmdAppendOption(final String shortName, final String longName,
739 final String description, final String argDesc) {
740 this(shortName, longName, description, argDesc, null, " ");
741 }
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756 public CmdAppendOption(final String shortName, final String longName,
757 final String description, final String argDesc,
758 final String defaultValue, final String separator) {
759 super(shortName, longName, description, argDesc, defaultValue, true);
760 this.separator = separator;
761 }
762
763 @Override
764 void setValue(final CommandLine commandLine, final String value)
765 throws InvalidCommandLineException {
766 if (value == null) return;
767 final String prevValue = (String) commandLine.getOptionValue(this);
768
769 if (prevValue == null) {
770 commandLine.setOptionValue(this, value);
771 } else {
772 commandLine.setOptionValue(this, prevValue + separator + value);
773 }
774 }
775 }
776
777
778
779
780
781
782 public static class CmdPathOption extends CmdAppendOption {
783
784
785
786
787
788
789
790
791
792
793
794 public CmdPathOption(final String shortName, final String longName,
795 final String description, final String argDesc) {
796 super(shortName, longName, description, argDesc, null, File.pathSeparator);
797 }
798
799
800
801
802
803
804 public List<String> getPathValue(final CommandLine commandLine) {
805 final String value = getValue(commandLine);
806 if (value == null)
807 return null;
808 else
809 return parsePathList(value);
810 }
811 }
812 }