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