1
2
3
4
5
6
7
8
9
10
11
12
13 package org.eclipse.jetty.start;
14
15 import java.io.BufferedReader;
16 import java.io.File;
17 import java.io.FileFilter;
18 import java.io.FileInputStream;
19 import java.io.FileNotFoundException;
20 import java.io.FileReader;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.io.OutputStream;
25 import java.io.PrintStream;
26 import java.io.Reader;
27 import java.lang.reflect.InvocationTargetException;
28 import java.lang.reflect.Method;
29 import java.net.ConnectException;
30 import java.net.InetAddress;
31 import java.net.Socket;
32 import java.security.Policy;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.List;
37 import java.util.Set;
38 import java.util.TimeZone;
39
40 import org.eclipse.jetty.start.log.RedirectedStreamLogger;
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class Main
55 {
56 private boolean _showUsage = false;
57 private boolean _dumpVersions = false;
58 private boolean _listOptions = false;
59 private boolean _dryRun = false;
60 private boolean _secure = false;
61 private boolean _fromDaemon = false;
62 private List<String> _activeOptions = new ArrayList<String>();
63 private Config _config = new Config();
64
65 private String _jettyHome;
66
67 public static void main(String[] args)
68 {
69 Main main = new Main();
70 try
71 {
72 main.parseCommandLine(args);
73 }
74 catch (Throwable t)
75 {
76 t.printStackTrace(System.err);
77 }
78 }
79
80 public void parseCommandLine(String[] args)
81 {
82 try
83 {
84 List<String> arguments = new ArrayList<String>();
85 arguments.addAll(Arrays.asList(args));
86 arguments.addAll(loadStartIni());
87
88
89 List<String> xmls = new ArrayList<String>();
90
91 for (String arg : arguments)
92 {
93 if ("--help".equals(arg))
94 {
95 _showUsage = true;
96 continue;
97 }
98
99 if ("--stop".equals(arg))
100 {
101 int port = Integer.parseInt(_config.getProperty("STOP.PORT","-1"));
102 String key = _config.getProperty("STOP.KEY",null);
103 stop(port,key);
104 return;
105 }
106
107 if ("--version".equals(arg) || "-v".equals(arg) || "--info".equals(arg))
108 {
109 _dumpVersions = true;
110 continue;
111 }
112
113 if ("--list-modes".equals(arg) || "--list-options".equals(arg))
114 {
115 _listOptions = true;
116 continue;
117 }
118
119 if ("--exec-print".equals(arg)||"--dry-run".equals(arg))
120 {
121 _dryRun = true;
122 continue;
123 }
124
125
126 if ("--fromDaemon".equals(arg))
127 {
128 _fromDaemon = true;
129 PrintStream logger = new PrintStream(new RedirectedStreamLogger("daemon_yyyy_mm_dd.log",false,90,TimeZone.getTimeZone("GMT")));
130 System.setOut(logger);
131 System.setErr(logger);
132 continue;
133 }
134
135 if ("--secure".equals(arg))
136 {
137 _secure = true;
138 continue;
139 }
140
141
142 if (arg.indexOf('=') >= 0)
143 {
144 processProperty(arg);
145 continue;
146 }
147
148
149 xmls.add(arg);
150 }
151
152 start(xmls);
153 }
154 catch (Throwable t)
155 {
156 t.printStackTrace(System.err);
157 usage();
158 }
159 }
160
161 private void processProperty(String arg)
162 {
163 String[] prop = arg.split("=",2);
164
165 if (prop[0].startsWith("-D"))
166 {
167
168 if (prop.length == 2)
169 {
170 setSystemProperty(prop[0].substring(2),prop[1]);
171 }
172 else
173 {
174 System.err.println("Unable to set value-less System Property: " + prop[0]);
175 }
176 }
177 else
178 {
179
180 if (prop.length == 2)
181 {
182
183 if ("OPTIONS".equals(prop[0]))
184 {
185 String ids[] = prop[1].split(",");
186 for (String id : ids)
187 {
188 if (!_activeOptions.contains(id))
189 {
190 _activeOptions.add(id);
191 }
192 }
193 _activeOptions.addAll(Arrays.asList(ids));
194 }
195 else
196 {
197 _config.setProperty(prop[0],prop[1]);
198 }
199 }
200 else
201 {
202 _config.setProperty(prop[0],null);
203 }
204 }
205 }
206
207
208
209
210 private List<String> loadStartIni()
211 {
212 File startIniFile = new File("start.ini");
213 if (!startIniFile.exists())
214 {
215
216 return Collections.emptyList();
217 }
218
219 List<String> args = new ArrayList<String>();
220
221 FileReader reader = null;
222 BufferedReader buf = null;
223 try
224 {
225 reader = new FileReader(startIniFile);
226 buf = new BufferedReader(reader);
227
228 String arg;
229 while ((arg = buf.readLine()) != null)
230 {
231
232 if (arg.indexOf('=') >= 0)
233 {
234
235 if (arg.startsWith("-D"))
236 {
237 String[] assign = arg.substring(2).split("=",2);
238
239 if (assign.length == 2)
240 {
241 System.setProperty(assign[0],assign[1]);
242 }
243 else
244 {
245 System.err.printf("Unable to set System Property '%s', no value provided%n",assign[0]);
246 }
247 }
248 else
249
250 {
251 String[] assign = arg.split("=",2);
252
253 if (assign.length == 2)
254 {
255 this._config.setProperty(assign[0],assign[1]);
256 }
257 else
258 {
259 this._config.setProperty(assign[0],null);
260 }
261 }
262 }
263 else
264
265 {
266 args.add(arg);
267 }
268 }
269 }
270 catch (IOException e)
271 {
272 e.printStackTrace();
273 }
274 finally
275 {
276 close(buf);
277 close(reader);
278 }
279
280 return args;
281 }
282
283 private void setSystemProperty(String key, String value)
284 {
285 _config.setProperty(key,value);
286 }
287
288 private void usage()
289 {
290 String usageResource = "org/eclipse/jetty/start/usage.txt";
291 InputStream usageStream = getClass().getClassLoader().getResourceAsStream(usageResource);
292
293 if (usageStream == null)
294 {
295 System.err.println("Usage: java -jar start.jar [options] [properties] [configs]");
296 System.err.println("ERROR: detailed usage resource unavailable");
297 System.exit(1);
298 }
299
300 BufferedReader buf = null;
301 try
302 {
303 buf = new BufferedReader(new InputStreamReader(usageStream));
304 String line;
305
306 while ((line = buf.readLine()) != null)
307 {
308 if (line.startsWith("@OPTIONS@"))
309 {
310 List<String> sortedOptions = new ArrayList<String>();
311 sortedOptions.addAll(_config.getSectionIds());
312 Collections.sort(sortedOptions);
313
314 System.err.println(" Available OPTIONS: ");
315
316 for (String option : sortedOptions)
317 {
318 System.err.println(" [" + option + "]");
319 }
320 }
321 else if (line.startsWith("@CONFIGS@"))
322 {
323 System.err.println(" Configurations Available in ${jetty.home}/etc/: ");
324 File etc = new File(System.getProperty("jetty.home","."),"etc");
325 if (!etc.exists())
326 {
327 System.err.println(" Unable to find " + etc);
328 continue;
329 }
330
331 if (!etc.isDirectory())
332 {
333 System.err.println(" Unable list dir " + etc);
334 continue;
335 }
336
337 File configs[] = etc.listFiles(new FileFilter()
338 {
339 public boolean accept(File path)
340 {
341 if (!path.isFile())
342 {
343 return false;
344 }
345
346 String name = path.getName().toLowerCase();
347 return (name.startsWith("jetty") && name.endsWith(".xml"));
348 }
349 });
350
351 List<File> configFiles = new ArrayList<File>();
352 configFiles.addAll(Arrays.asList(configs));
353 Collections.sort(configFiles);
354
355 for (File configFile : configFiles)
356 {
357 System.err.println(" etc/" + configFile.getName());
358 }
359 }
360 else
361 {
362 System.err.println(line);
363 }
364 }
365 }
366 catch (IOException e)
367 {
368 e.printStackTrace(System.err);
369 }
370 finally
371 {
372 if (buf != null)
373 {
374 try
375 {
376 buf.close();
377 }
378 catch (IOException ignore)
379 {
380
381 }
382 }
383 }
384 System.exit(1);
385 }
386
387 public void invokeMain(ClassLoader classloader, String classname, List<String> args) throws IllegalAccessException, InvocationTargetException,
388 NoSuchMethodException, ClassNotFoundException
389 {
390 Class<?> invoked_class = null;
391
392 try
393 {
394 invoked_class = classloader.loadClass(classname);
395 }
396 catch (ClassNotFoundException e)
397 {
398
399 }
400
401 if (Config.isDebug() || invoked_class == null)
402 {
403 if (invoked_class == null)
404 System.err.println("ClassNotFound: " + classname);
405 else
406 System.err.println(classname + " " + invoked_class.getPackage().getImplementationVersion());
407
408 if (invoked_class == null)
409 {
410 usage();
411 return;
412 }
413 }
414
415 String argArray[] = args.toArray(new String[0]);
416
417 Class<?>[] method_param_types = new Class[]
418 { argArray.getClass() };
419
420 Method main = invoked_class.getDeclaredMethod("main",method_param_types);
421 Object[] method_params = new Object[]
422 { argArray };
423
424 main.invoke(null,method_params);
425 }
426
427
428 public static void close(Reader reader)
429 {
430 if (reader == null)
431 {
432 return;
433 }
434 try
435 {
436 reader.close();
437 }
438 catch (IOException e)
439 {
440 e.printStackTrace();
441 }
442 }
443
444
445 public static void close(InputStream stream)
446 {
447 if (stream == null)
448 {
449 return;
450 }
451 try
452 {
453 stream.close();
454 }
455 catch (IOException e)
456 {
457 e.printStackTrace();
458 }
459 }
460
461
462 public void start(List<String> xmls) throws FileNotFoundException
463 {
464
465 startMonitor();
466
467
468 if (_activeOptions.isEmpty())
469 {
470 _activeOptions.add("default");
471 _activeOptions.add("*");
472 }
473
474
475 if (_secure)
476 {
477 addMandatoryOption("secure");
478 addMandatoryOption("security");
479 }
480
481
482 if (xmls.isEmpty())
483 {
484
485
486 if (_fromDaemon)
487 {
488 xmls.add("etc/jetty-logging.xml");
489 }
490 xmls.add("etc/jetty.xml");
491 }
492
493
494 initConfig(xmls);
495
496
497 xmls = resolveXmlConfigs(xmls);
498
499
500 Classpath classpath = _config.getCombinedClasspath(_activeOptions);
501
502 System.setProperty("java.class.path",classpath.toString());
503 ClassLoader cl = classpath.getClassLoader();
504 if (Config.isDebug())
505 {
506 System.err.println("java.class.path=" + System.getProperty("java.class.path"));
507 System.err.println("jetty.home=" + System.getProperty("jetty.home"));
508 System.err.println("java.home=" + System.getProperty("java.home"));
509 System.err.println("java.io.tmpdir=" + System.getProperty("java.io.tmpdir"));
510 System.err.println("java.class.path=" + classpath);
511 System.err.println("classloader=" + cl);
512 System.err.println("classloader.parent=" + cl.getParent());
513 }
514
515
516 if (_showUsage)
517 {
518 usage();
519 return;
520 }
521
522
523 if (_dumpVersions)
524 {
525 showClasspathWithVersions(classpath);
526 return;
527 }
528
529
530 if (_listOptions)
531 {
532 showAllOptionsWithVersions(classpath);
533 return;
534 }
535
536
537 if (_dryRun)
538 {
539 showDryRun(classpath,xmls);
540 return;
541 }
542
543
544 Thread.currentThread().setContextClassLoader(cl);
545
546
547 initSecurity(cl);
548
549
550 try
551 {
552
553 String classname = _config.getMainClassname();
554
555
556 String mainClass = System.getProperty("jetty.server");
557 if (mainClass != null)
558 classname = mainClass;
559
560
561 mainClass = System.getProperty("main.class");
562 if (mainClass != null)
563 classname = mainClass;
564
565 Config.debug("main.class=" + classname);
566
567 invokeMain(cl,classname,xmls);
568 }
569 catch (Exception e)
570 {
571 e.printStackTrace();
572 }
573 }
574
575 private String resolveXmlConfig(String xmlFilename) throws FileNotFoundException
576 {
577 File xml = new File(xmlFilename);
578 if (xml.exists() && xml.isFile())
579 {
580 return xml.getAbsolutePath();
581 }
582
583 xml = new File(_jettyHome,fixPath(xmlFilename));
584 if (xml.exists() && xml.isFile())
585 {
586 return xml.getAbsolutePath();
587 }
588
589 xml = new File(_jettyHome,fixPath("etc/" + xmlFilename));
590 if (xml.exists() && xml.isFile())
591 {
592 return xml.getAbsolutePath();
593 }
594
595 throw new FileNotFoundException("Unable to find XML Config: " + xmlFilename);
596 }
597
598 private void addMandatoryOption(String id)
599 {
600 if (!_activeOptions.contains(id))
601 {
602 _activeOptions.add(id);
603 }
604 }
605
606 private void showDryRun(Classpath classpath, List<String> xmls)
607 {
608 StringBuffer cmd = new StringBuffer();
609
610 cmd.append(findJavaBin());
611 cmd.append(" -cp ").append(classpath.toString());
612 cmd.append(" -Djetty.home=").append(_jettyHome);
613 cmd.append(" ").append(_config.getMainClassname());
614 for (String xml : xmls)
615 {
616 cmd.append(" ").append(xml);
617 }
618
619 System.out.println(cmd);
620 }
621
622 private String findJavaBin()
623 {
624 File javaHome = new File(System.getProperty("java.home"));
625 if (!javaHome.exists())
626 {
627 return null;
628 }
629
630 File javabin = findExecutable(javaHome,"bin/java");
631 if (javabin != null)
632 {
633 return javabin.getAbsolutePath();
634 }
635
636 javabin = findExecutable(javaHome,"bin/java.exe");
637 if (javabin != null)
638 {
639 return javabin.getAbsolutePath();
640 }
641
642 return "java";
643 }
644
645 private File findExecutable(File root, String path)
646 {
647 String npath = path.replace('/',File.separatorChar);
648 File exe = new File(root,npath);
649 if (!exe.exists())
650 {
651 return null;
652 }
653 return exe;
654 }
655
656 private void showAllOptionsWithVersions(Classpath classpath)
657 {
658 Set<String> sectionIds = _config.getSectionIds();
659
660 StringBuffer msg = new StringBuffer();
661 msg.append("There ");
662 if (sectionIds.size() > 1)
663 {
664 msg.append("are ");
665 }
666 else
667 {
668 msg.append("is ");
669 }
670 msg.append(String.valueOf(sectionIds.size()));
671 msg.append(" OPTION");
672 if (sectionIds.size() > 1)
673 {
674 msg.append("s");
675 }
676 msg.append(" available to use.");
677 System.out.println(msg);
678 System.out.println("Each option is listed along with associated available classpath entries, in the order that they would appear from that mode.");
679 System.out.println("Note: If using multiple options (eg: 'Server,servlet,webapp,jms,jmx') "
680 + "then overlapping entries will not be repeated in the eventual classpath.");
681 System.out.println();
682 System.out.printf("${jetty.home} = %s%n",_jettyHome);
683 System.out.println();
684
685 for (String sectionId : sectionIds)
686 {
687 if (Config.DEFAULT_SECTION.equals(sectionId))
688 {
689 System.out.println("GLOBAL option (Prepended Entries)");
690 }
691 else if ("*".equals(sectionId))
692 {
693 System.out.println("GLOBAL option (Appended Entries) (*)");
694 }
695 else
696 {
697 System.out.printf("Option [%s]",sectionId);
698 if (Character.isUpperCase(sectionId.charAt(0)))
699 {
700 System.out.print(" (Aggregate)");
701 }
702 System.out.println();
703 }
704 System.out.println("-------------------------------------------------------------");
705
706 Classpath sectionCP = _config.getSectionClasspath(sectionId);
707
708 if (sectionCP.isEmpty())
709 {
710 System.out.println("Empty option, no classpath entries active.");
711 System.out.println();
712 continue;
713 }
714
715 int i = 0;
716 for (File element : sectionCP.getElements())
717 {
718 String elementPath = element.getAbsolutePath();
719 if (elementPath.startsWith(_jettyHome))
720 {
721 elementPath = "${jetty.home}" + elementPath.substring(_jettyHome.length());
722 }
723 System.out.printf("%2d: %20s | %s\n",i++,getVersion(element),elementPath);
724 }
725
726 System.out.println();
727 }
728 }
729
730 private void showClasspathWithVersions(Classpath classpath)
731 {
732
733
734
735 System.out.println("Active Options: " + _activeOptions);
736
737 if (classpath.count() == 0)
738 {
739 System.out.println("No version information available show.");
740 return;
741 }
742
743 System.out.println("Version Information on " + classpath.count() + " entr" + ((classpath.count() > 1)?"ies":"y") + " in the classpath.");
744 System.out.println("Note: order presented here is how they would appear on the classpath.");
745 System.out.println(" changes to the OPTIONS=[option,option,...] command line option will be reflected here.");
746
747 int i = 0;
748 for (File element : classpath.getElements())
749 {
750 String elementPath = element.getAbsolutePath();
751 if (elementPath.startsWith(_jettyHome))
752 {
753 elementPath = "${jetty.home}" + elementPath.substring(_jettyHome.length());
754 }
755 System.out.printf("%2d: %20s | %s\n",i++,getVersion(element),elementPath);
756 }
757 }
758
759 private String fixPath(String path)
760 {
761 return path.replace('/',File.separatorChar);
762 }
763
764 private String getVersion(File element)
765 {
766 if (element.isDirectory())
767 {
768 return "(dir)";
769 }
770
771 if (element.isFile())
772 {
773 String name = element.getName().toLowerCase();
774 if (name.endsWith(".jar"))
775 {
776 return JarVersion.getVersion(element);
777 }
778
779 if (name.endsWith(".zip"))
780 {
781 return getZipVersion(element);
782 }
783 }
784
785 return "";
786 }
787
788 private String getZipVersion(File element)
789 {
790
791 return "";
792 }
793
794 private void initSecurity(ClassLoader cl)
795 {
796
797 try
798 {
799 if (_secure)
800 {
801 Policy.setPolicy(_config.getPolicyInstance(cl));
802 System.setSecurityManager(new SecurityManager());
803 }
804 else
805 {
806 Policy policy = Policy.getPolicy();
807 if (policy != null)
808 policy.refresh();
809 }
810 }
811 catch (Exception e)
812 {
813 e.printStackTrace();
814 }
815 }
816
817 private List<String> resolveXmlConfigs(List<String> xmls) throws FileNotFoundException
818 {
819 List<String> ret = new ArrayList<String>();
820 for (String xml : xmls)
821 {
822 ret.add(resolveXmlConfig(xml));
823 }
824
825 return ret;
826 }
827
828 private void initConfig(List<String> xmls)
829 {
830 InputStream cfgstream = null;
831 try
832 {
833 _config.setArgCount(xmls.size());
834
835
836 String cfgName = _config.getProperty("START","org/eclipse/jetty/start/start.config");
837 Config.debug("config=" + cfgName);
838
839
840 cfgstream = getClass().getClassLoader().getResourceAsStream(cfgName);
841
842
843 if (cfgstream == null)
844 cfgstream = new FileInputStream(cfgName);
845
846
847 _config.parse(cfgstream);
848
849 _jettyHome = _config.getProperty("jetty.home");
850 if (_jettyHome != null)
851 {
852 _jettyHome = new File(_jettyHome).getCanonicalPath();
853 System.setProperty("jetty.home",_jettyHome);
854 }
855 }
856 catch (Exception e)
857 {
858 e.printStackTrace();
859 System.exit(1);
860 }
861 finally
862 {
863 close(cfgstream);
864 }
865 }
866
867 private void startMonitor()
868 {
869 int port = Integer.parseInt(_config.getProperty("STOP.PORT","-1"));
870 String key = _config.getProperty("STOP.KEY",null);
871
872 Monitor.monitor(port,key);
873 }
874
875
876
877
878 public void stop(int port, String key)
879 {
880 int _port = port;
881 String _key = key;
882
883 try
884 {
885 if (_port <= 0)
886 System.err.println("STOP.PORT system property must be specified");
887 if (_key == null)
888 {
889 _key = "";
890 System.err.println("STOP.KEY system property must be specified");
891 System.err.println("Using empty key");
892 }
893
894 Socket s = new Socket(InetAddress.getByName("127.0.0.1"),_port);
895 OutputStream out = s.getOutputStream();
896 out.write((_key + "\r\nstop\r\n").getBytes());
897 out.flush();
898 s.close();
899 }
900 catch (ConnectException e)
901 {
902 System.err.println("ERROR: Not running!");
903 }
904 catch (Exception e)
905 {
906 e.printStackTrace();
907 }
908 }
909 }