1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.start;
20
21 import static org.eclipse.jetty.start.UsageException.ERR_BAD_ARG;
22
23 import java.io.File;
24 import java.io.FileFilter;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.Enumeration;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Properties;
36 import java.util.Set;
37
38
39
40
41 public class StartArgs
42 {
43 public static final String CMD_LINE_SOURCE = "<cmd-line>";
44 public static final String VERSION;
45
46 static
47 {
48 String ver = System.getProperty("jetty.version",null);
49
50 if (ver == null)
51 {
52 Package pkg = StartArgs.class.getPackage();
53 if ((pkg != null) && "Eclipse.org - Jetty".equals(pkg.getImplementationVendor()) && (pkg.getImplementationVersion() != null))
54 {
55 ver = pkg.getImplementationVersion();
56 }
57 }
58
59 if (ver == null)
60 {
61 ver = "TEST";
62 }
63
64 VERSION = ver;
65 System.setProperty("jetty.version",VERSION);
66 }
67
68 private static final String SERVER_MAIN = "org.eclipse.jetty.xml.XmlConfiguration";
69
70 private List<String> commandLine = new ArrayList<>();
71 private Set<String> modules = new HashSet<>();
72 private Map<String, List<String>> sources = new HashMap<>();
73 private List<FileArg> files = new ArrayList<>();
74 private Classpath classpath;
75 private List<String> xmlRefs = new ArrayList<>();
76 private List<File> xmls = new ArrayList<>();
77 private Properties properties = new Properties();
78 private Set<String> systemPropertyKeys = new HashSet<>();
79 private List<String> jvmArgs = new ArrayList<>();
80 private List<String> moduleStartdIni = new ArrayList<>();
81 private List<String> moduleStartIni = new ArrayList<>();
82 private Map<String, String> propertySource = new HashMap<>();
83 private String moduleGraphFilename;
84
85 private Modules allModules;
86
87 private boolean run = true;
88 private boolean help = false;
89 private boolean stopCommand = false;
90 private boolean listModules = false;
91 private boolean listClasspath = false;
92 private boolean listConfig = false;
93 private boolean version = false;
94 private boolean dryRun = false;
95
96 private boolean exec = false;
97
98 public StartArgs(String[] commandLineArgs)
99 {
100 commandLine.addAll(Arrays.asList(commandLineArgs));
101 classpath = new Classpath();
102 }
103
104 private void addFile(String uriLocation)
105 {
106 FileArg arg = new FileArg(uriLocation);
107 if (!files.contains(arg))
108 {
109 files.add(arg);
110 }
111 }
112
113 public void addSystemProperty(String key, String value)
114 {
115 this.systemPropertyKeys.add(key);
116 System.setProperty(key,value);
117 }
118
119 private void addUniqueXmlFile(String xmlRef, File xmlfile) throws IOException
120 {
121 if (!FS.canReadFile(xmlfile))
122 {
123 throw new IOException("Cannot read file: " + xmlRef);
124 }
125 xmlfile = xmlfile.getCanonicalFile();
126 if (!xmls.contains(xmlfile))
127 {
128 xmls.add(xmlfile);
129 }
130 }
131
132 public void dumpActiveXmls(BaseHome baseHome)
133 {
134 System.out.println();
135 System.out.println("Jetty Active XMLs:");
136 System.out.println("------------------");
137 if (xmls.isEmpty())
138 {
139 System.out.println(" (no xml files specified)");
140 return;
141 }
142
143 for (File xml : xmls)
144 {
145 System.out.printf(" %s%n",baseHome.toShortForm(xml.getAbsolutePath()));
146 }
147 }
148
149 public void dumpEnvironment()
150 {
151
152 System.out.println();
153 System.out.println("Java Environment:");
154 System.out.println("-----------------");
155 dumpSystemProperty("java.home");
156 dumpSystemProperty("java.vm.vendor");
157 dumpSystemProperty("java.vm.version");
158 dumpSystemProperty("java.vm.name");
159 dumpSystemProperty("java.vm.info");
160 dumpSystemProperty("java.runtime.name");
161 dumpSystemProperty("java.runtime.version");
162 dumpSystemProperty("java.io.tmpdir");
163
164
165 System.out.println();
166 System.out.println("Jetty Environment:");
167 System.out.println("-----------------");
168
169 dumpSystemProperty("jetty.home");
170 dumpSystemProperty("jetty.base");
171 dumpSystemProperty("jetty.version");
172 }
173
174 public void dumpJvmArgs()
175 {
176 System.out.println();
177 System.out.println("JVM Arguments:");
178 System.out.println("--------------");
179 if (jvmArgs.isEmpty())
180 {
181 System.out.println(" (no jvm args specified)");
182 return;
183 }
184
185 for (String jvmArgKey : jvmArgs)
186 {
187 String value = System.getProperty(jvmArgKey);
188 if (value != null)
189 {
190 System.out.printf(" %s = %s%n",jvmArgKey,value);
191 }
192 else
193 {
194 System.out.printf(" %s%n",jvmArgKey);
195 }
196 }
197 }
198
199 public void dumpProperties()
200 {
201 System.out.println();
202 System.out.println("Properties:");
203 System.out.println("-----------");
204
205 if (properties.isEmpty())
206 {
207 System.out.println(" (no properties specified)");
208 return;
209 }
210
211 List<String> sortedKeys = new ArrayList<>();
212 @SuppressWarnings("unchecked")
213 Enumeration<String> keyEnum = (Enumeration<String>)properties.propertyNames();
214 while (keyEnum.hasMoreElements())
215 {
216 sortedKeys.add(keyEnum.nextElement());
217 }
218
219 Collections.sort(sortedKeys);
220
221 for (String key : sortedKeys)
222 {
223 String value = properties.getProperty(key);
224 System.out.printf(" %s = %s%n",key,value);
225 }
226 }
227
228 public void dumpSystemProperties()
229 {
230 System.out.println();
231 System.out.println("System Properties:");
232 System.out.println("------------------");
233
234 if (systemPropertyKeys.isEmpty())
235 {
236 System.out.println(" (no system properties specified)");
237 return;
238 }
239
240 List<String> sortedKeys = new ArrayList<>();
241 sortedKeys.addAll(systemPropertyKeys);
242 Collections.sort(sortedKeys);
243
244 for (String key : sortedKeys)
245 {
246 String value = System.getProperty(key);
247 System.out.printf(" %s = %s%n",key,value);
248 }
249 }
250
251 private void dumpSystemProperty(String key)
252 {
253 System.out.printf(" %s=%s%n",key,System.getProperty(key));
254 }
255
256
257
258
259
260
261
262 private void ensureSystemPropertySet(String key)
263 {
264 if (systemPropertyKeys.contains(key))
265 {
266 return;
267 }
268
269 if (properties.containsKey(key))
270 {
271 String val = properties.getProperty(key,null);
272 if (val == null)
273 {
274 return;
275 }
276
277 systemPropertyKeys.add(key);
278 System.setProperty(key,val);
279 }
280 }
281
282
283
284
285
286
287
288
289 public void expandModules(BaseHome baseHome, List<Module> activeModules) throws IOException
290 {
291 for (Module module : activeModules)
292 {
293
294 for (String rawlibref : module.getLibs())
295 {
296 String libref = rawlibref.replace("${jetty.version}",VERSION);
297 libref = FS.separators(libref);
298
299 if (libref.contains("*"))
300 {
301
302 int idx = libref.lastIndexOf(File.separatorChar);
303
304 String relativePath = "/";
305 String filenameRef = libref;
306 if (idx >= 0)
307 {
308 relativePath = libref.substring(0,idx);
309 filenameRef = libref.substring(idx + 1);
310 }
311
312 StringBuilder regex = new StringBuilder();
313 regex.append('^');
314 for (char c : filenameRef.toCharArray())
315 {
316 switch (c)
317 {
318 case '*':
319 regex.append(".*");
320 break;
321 case '.':
322 regex.append("\\.");
323 break;
324 default:
325 regex.append(c);
326 }
327 }
328 regex.append('$');
329
330 FileFilter filter = new FS.FilenameRegexFilter(regex.toString());
331
332 for (File libfile : baseHome.listFiles(relativePath,filter))
333 {
334 classpath.addComponent(libfile);
335 }
336 }
337 else
338 {
339
340 File libfile = baseHome.getFile(libref);
341 classpath.addComponent(libfile);
342 }
343 }
344
345
346 for (String xmlRef : module.getXmls())
347 {
348
349 File xmlfile = baseHome.getFile(xmlRef);
350 addUniqueXmlFile(xmlRef,xmlfile);
351 }
352
353
354 for (String file : module.getFiles())
355 {
356 StartLog.debug("Adding module specified file: %s",file);
357 addFile(file);
358 }
359 }
360 }
361
362 public Modules getAllModules()
363 {
364 return allModules;
365 }
366
367 public Classpath getClasspath()
368 {
369 return classpath;
370 }
371
372 public List<String> getCommandLine()
373 {
374 return this.commandLine;
375 }
376
377 public List<FileArg> getFiles()
378 {
379 return files;
380 }
381
382 public Set<String> getEnabledModules()
383 {
384 return this.modules;
385 }
386
387 public List<String> getJvmArgs()
388 {
389 return jvmArgs;
390 }
391
392 public CommandLineBuilder getMainArgs(BaseHome baseHome, boolean addJavaInit) throws IOException
393 {
394 CommandLineBuilder cmd = new CommandLineBuilder();
395
396 if (addJavaInit)
397 {
398 cmd.addArg(CommandLineBuilder.findJavaBin());
399
400 for (String x : jvmArgs)
401 {
402 cmd.addArg(x);
403 }
404
405 cmd.addRawArg("-Djetty.home=" + baseHome.getHome());
406 cmd.addRawArg("-Djetty.base=" + baseHome.getBase());
407
408
409 for (String propKey : systemPropertyKeys)
410 {
411 String value = System.getProperty(propKey);
412 cmd.addEqualsArg("-D" + propKey,value);
413 }
414
415 cmd.addArg("-cp");
416 cmd.addRawArg(classpath.toString());
417 cmd.addRawArg(getMainClassname());
418 }
419
420
421 ensureSystemPropertySet("STOP.PORT");
422 ensureSystemPropertySet("STOP.KEY");
423 ensureSystemPropertySet("STOP.WAIT");
424
425
426 if (properties.size() > 0)
427 {
428 File prop_file = File.createTempFile("start",".properties");
429 if (!dryRun)
430 {
431 prop_file.deleteOnExit();
432 }
433 try (FileOutputStream out = new FileOutputStream(prop_file))
434 {
435 properties.store(out,"start.jar properties");
436 }
437 cmd.addArg(prop_file.getAbsolutePath());
438 }
439
440 for (File xml : xmls)
441 {
442 cmd.addRawArg(xml.getAbsolutePath());
443 }
444
445 return cmd;
446 }
447
448 public String getMainClassname()
449 {
450 String mainclass = System.getProperty("jetty.server",SERVER_MAIN);
451 return System.getProperty("main.class",mainclass);
452 }
453
454 public String getModuleGraphFilename()
455 {
456 return moduleGraphFilename;
457 }
458
459 public List<String> getModuleStartdIni()
460 {
461 return moduleStartdIni;
462 }
463
464 public List<String> getModuleStartIni()
465 {
466 return moduleStartIni;
467 }
468
469 public Properties getProperties()
470 {
471 return properties;
472 }
473
474 public List<String> getSources(String module)
475 {
476 return sources.get(module);
477 }
478
479 private String getValue(String arg)
480 {
481 int idx = arg.indexOf('=');
482 if (idx == (-1))
483 {
484 throw new UsageException(ERR_BAD_ARG,"Argument is missing a required value: %s",arg);
485 }
486 String value = arg.substring(idx + 1).trim();
487 if (value.length() <= 0)
488 {
489 throw new UsageException(ERR_BAD_ARG,"Argument is missing a required value: %s",arg);
490 }
491 return value;
492 }
493
494 private List<String> getValues(String arg)
495 {
496 String v = getValue(arg);
497 ArrayList<String> l = new ArrayList<>();
498 for (String s : v.split(","))
499 {
500 if (s != null)
501 {
502 s = s.trim();
503 if (s.length() > 0)
504 {
505 l.add(s);
506 }
507 }
508 }
509 return l;
510 }
511
512 public List<File> getXmlFiles()
513 {
514 return xmls;
515 }
516
517 public boolean hasJvmArgs()
518 {
519 return jvmArgs.size() > 0;
520 }
521
522 public boolean hasSystemProperties()
523 {
524 for (String key : systemPropertyKeys)
525 {
526
527 if ("jetty.home".equals(key) || "jetty.base".equals(key))
528 {
529
530 continue;
531 }
532 return true;
533 }
534 return false;
535 }
536
537 public boolean isDryRun()
538 {
539 return dryRun;
540 }
541
542 public boolean isExec()
543 {
544 return exec;
545 }
546
547 public boolean isHelp()
548 {
549 return help;
550 }
551
552 public boolean isListClasspath()
553 {
554 return listClasspath;
555 }
556
557 public boolean isListConfig()
558 {
559 return listConfig;
560 }
561
562 public boolean isListModules()
563 {
564 return listModules;
565 }
566
567 public boolean isRun()
568 {
569 return run;
570 }
571
572 public boolean isStopCommand()
573 {
574 return stopCommand;
575 }
576
577 public boolean isVersion()
578 {
579 return version;
580 }
581
582 public void parse(BaseHome baseHome, TextFile file)
583 {
584 String source;
585 try
586 {
587 source = baseHome.toShortForm(file.getFile());
588 }
589 catch (Exception e)
590 {
591 throw new UsageException(ERR_BAD_ARG,"Bad file: %s",file);
592 }
593 for (String line : file)
594 {
595 parse(line,source);
596 }
597 }
598
599 public void parse(final String rawarg, String source)
600 {
601 if (rawarg == null)
602 {
603 return;
604 }
605
606 final String arg = rawarg.trim();
607
608 if (arg.length() <= 0)
609 {
610 return;
611 }
612
613 if (arg.startsWith("#"))
614 {
615 return;
616 }
617
618 if ("--help".equals(arg) || "-?".equals(arg))
619 {
620 if (!CMD_LINE_SOURCE.equals(source))
621 {
622 throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source);
623 }
624
625 help = true;
626 run = false;
627 return;
628 }
629
630 if ("--debug".equals(arg))
631 {
632
633 return;
634 }
635
636 if ("--stop".equals(arg))
637 {
638 if (!CMD_LINE_SOURCE.equals(source))
639 {
640 throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source);
641 }
642 stopCommand = true;
643 run = false;
644 return;
645 }
646
647 if (arg.startsWith("--download="))
648 {
649 addFile(getValue(arg));
650 return;
651 }
652
653 if ("--list-classpath".equals(arg) || "--version".equals(arg) || "-v".equals(arg) || "--info".equals(arg))
654 {
655 listClasspath = true;
656 run = false;
657 return;
658 }
659
660 if ("--list-config".equals(arg))
661 {
662 listConfig = true;
663 run = false;
664 return;
665 }
666
667 if ("--dry-run".equals(arg) || "--exec-print".equals(arg))
668 {
669 if (!CMD_LINE_SOURCE.equals(source))
670 {
671 throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source);
672 }
673 dryRun = true;
674 run = false;
675 return;
676 }
677
678 if ("--exec".equals(arg))
679 {
680 exec = true;
681 return;
682 }
683
684
685
686 if (arg.startsWith("--lib="))
687 {
688 String cp = getValue(arg);
689 classpath.addClasspath(cp);
690 return;
691 }
692
693
694 if ("--list-modules".equals(arg))
695 {
696 listModules = true;
697 run = false;
698 return;
699 }
700
701 if (arg.startsWith("--add-to-startd"))
702 {
703 if (!CMD_LINE_SOURCE.equals(source))
704 {
705 throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source);
706 }
707 moduleStartdIni.addAll(getValues(arg));
708 run = false;
709 return;
710 }
711
712 if (arg.startsWith("--add-to-start"))
713 {
714 if (!CMD_LINE_SOURCE.equals(source))
715 {
716 throw new UsageException(ERR_BAD_ARG,"%s not allowed in %s",arg,source);
717 }
718 moduleStartIni.addAll(getValues(arg));
719 run = false;
720 return;
721 }
722
723 if (arg.startsWith("--module="))
724 {
725 for (String moduleName : getValues(arg))
726 {
727 modules.add(moduleName);
728 List<String> list = sources.get(moduleName);
729 if (list == null)
730 {
731 list = new ArrayList<String>();
732 sources.put(moduleName,list);
733 }
734 list.add(source);
735 }
736 return;
737 }
738
739 if (arg.startsWith("--write-module-graph="))
740 {
741 this.moduleGraphFilename = getValue(arg);
742 run = false;
743 return;
744 }
745
746
747 if (arg.startsWith("-D"))
748 {
749 String[] assign = arg.substring(2).split("=",2);
750 systemPropertyKeys.add(assign[0]);
751 switch (assign.length)
752 {
753 case 2:
754 System.setProperty(assign[0],assign[1]);
755 break;
756 case 1:
757 System.setProperty(assign[0],"");
758 break;
759 default:
760 break;
761 }
762 return;
763 }
764
765
766 if (arg.startsWith("-"))
767 {
768
769 if (!jvmArgs.contains(arg))
770 {
771 jvmArgs.add(arg);
772 }
773 return;
774 }
775
776
777 int idx = arg.indexOf('=');
778 if (idx >= 0)
779 {
780 String key = arg.substring(0,idx);
781 String value = arg.substring(idx + 1);
782
783 if (source != CMD_LINE_SOURCE)
784 {
785 if (propertySource.containsKey(key))
786 {
787 throw new UsageException(ERR_BAD_ARG,"Property %s in %s already set in %s",key,source,propertySource.get(key));
788 }
789 propertySource.put(key,source);
790 }
791
792 if ("OPTION".equals(key) || "OPTIONS".equals(key))
793 {
794 StringBuilder warn = new StringBuilder();
795 warn.append("The behavior of the argument ");
796 warn.append(arg).append(" (seen in ").append(source);
797 warn.append(") has changed, and is now considered a normal property. ");
798 warn.append(key).append(" no longer controls what libraries are on your classpath,");
799 warn.append(" use --module instead. See --help for details.");
800 StartLog.warn(warn.toString());
801 }
802
803 properties.setProperty(key,value);
804 return;
805 }
806
807
808 if (FS.isXml(arg))
809 {
810
811 if (!xmlRefs.contains(arg))
812 {
813 xmlRefs.add(arg);
814 }
815 return;
816 }
817
818
819 throw new UsageException(ERR_BAD_ARG,"Unrecognized argument: \"%s\" in %s",arg,source);
820 }
821
822 public void parseCommandLine()
823 {
824 for (String line : commandLine)
825 {
826 parse(line,StartArgs.CMD_LINE_SOURCE);
827 }
828 }
829
830 public void resolveExtraXmls(BaseHome baseHome) throws IOException
831 {
832
833 for (String xmlRef : xmlRefs)
834 {
835
836 File xmlfile = baseHome.getFile(xmlRef);
837 if (!xmlfile.exists())
838 {
839 xmlfile = baseHome.getFile("etc/" + xmlRef);
840 }
841 addUniqueXmlFile(xmlRef,xmlfile);
842 }
843 }
844
845 public void setAllModules(Modules allModules)
846 {
847 this.allModules = allModules;
848 }
849
850 @Override
851 public String toString()
852 {
853 StringBuilder builder = new StringBuilder();
854 builder.append("StartArgs [commandLine=");
855 builder.append(commandLine);
856 builder.append(", enabledModules=");
857 builder.append(modules);
858 builder.append(", xmlRefs=");
859 builder.append(xmlRefs);
860 builder.append(", properties=");
861 builder.append(properties);
862 builder.append(", jvmArgs=");
863 builder.append(jvmArgs);
864 builder.append("]");
865 return builder.toString();
866 }
867 }