View Javadoc

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