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.FileInputStream;
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.io.InputStreamReader;
21  import java.io.OutputStream;
22  import java.lang.reflect.Constructor;
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  import java.net.ConnectException;
26  import java.net.InetAddress;
27  import java.net.Socket;
28  import java.security.Policy;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Collections;
32  import java.util.HashMap;
33  import java.util.HashSet;
34  import java.util.Hashtable;
35  import java.util.Iterator;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Set;
39  import java.util.StringTokenizer;
40  
41  /*-------------------------------------------*/
42  /**
43   * Main start class. This class is intended to be the main class listed in the MANIFEST.MF of the
44   * start.jar archive. It allows an application to be started with the command "java -jar
45   * start.jar". The behaviour of Main is controlled by the "org/eclipse/start/start.config" file
46   * obtained as a resource or file. This can be overridden with the START system property. The
47   * format of each line in this file is:
48   * 
49   * <PRE>
50   * Each line contains entry in the format:
51   * 
52   *  SUBJECT [ [!] CONDITION [AND|OR] ]*
53   * 
54   * where SUBJECT: 
55   *   ends with ".class" is the Main class to run.
56   *   ends with ".xml" is a configuration file for the command line
57   *   ends with "/" is a directory from which to add all jar and zip files. 
58   *   ends with "/*" is a directory from which to add all unconsidered jar and zip files.
59   *   ends with "/**" is a directory from which to recursively add all unconsidered jar and zip files.
60   *   Containing = are used to assign system properties.
61   *   Containing ~= are used to assign start properties.
62   *   Containing /= are used to assign a canonical path.
63   *   all other subjects are treated as files to be added to the classpath.
64   * 
65   * ${name} is expanded to a start property
66   * $(name) is expanded to either a start property or a system property. 
67   * The start property ${version} is defined as the version of the start.jar
68   * 
69   * Files starting with "/" are considered absolute, all others are relative to
70   * the home directory.
71   * 
72   * CONDITION is one of:
73   *   always
74   *   never
75   *   available classname         - true if class on classpath
76   *   property name               - true if set as start property
77   *   system   name               - true if set as system property
78   *   exists file                 - true if file/dir exists
79   *   java OPERATOR version       - java version compared to literal
80   *   nargs OPERATOR number       - number of command line args compared to literal
81   *   OPERATOR := one of "<",">","<=",">=","==","!="
82   * 
83   * CONTITIONS can be combined with AND OR or !, with AND being the assume
84   * operator for a list of CONDITIONS.
85   * 
86   * Classpath operations are evaluated on the fly, so once a class or jar is
87   * added to the classpath, subsequent available conditions will see that class.
88   * 
89   * The configuration file may be divided into sections with option names like:
90   * [ssl,default]
91   * 
92   * Clauses after a section header will only be included if they match one of the tags in the 
93   * options property.  By default options are set to "default,*" or the OPTIONS property may
94   * be used to pass in a list of tags, eg. :
95   * 
96   *    java -jar start.jar OPTIONS=jetty,jsp,ssl
97   * 
98   * The tag '*' is always appended to the options, so any section with the * tag is always 
99   * applied.
100  * 
101  * </PRE>
102  * 
103  * 
104  */
105 public class Main
106 {
107     private static final String _version = (Main.class.getPackage()!=null && Main.class.getPackage().getImplementationVersion()!=null)
108         ?Main.class.getPackage().getImplementationVersion()
109         :System.getProperty("jetty.version", "Unknown");
110         
111     public static boolean DEBUG=false;
112     
113     private Map<String,String> _properties = new HashMap<String,String>();
114     
115     
116     private String _classname=null;
117     private Classpath _classpath=new Classpath();
118     
119     private boolean _showVersions=false;
120     private List<String> _xml=new ArrayList<String>();
121     private Set<String> _activeOptions = new HashSet<String>();
122     private Set<String> _options = new HashSet<String>();
123     private Set<String> _policies = new HashSet<String>();     
124     
125     /*
126     private String _config=System.getProperty("START","org/eclipse/jetty/start/start.config");
127     */
128     
129     public static void main(String[] args)
130     {
131         try
132         {
133             Main main=new Main();
134             List<String> arguments = new ArrayList<String>(Arrays.asList(args));
135             
136             for (int i=0; i<arguments.size(); i++)
137             {
138                 String arg=arguments.get(i);
139                 if (arg.equalsIgnoreCase("--help"))
140                 {
141                     usage();
142                 }
143                 
144                 if (arg.equalsIgnoreCase("--stop"))
145                 {
146                     int port = Integer.parseInt(main.getProperty("STOP.PORT","-1"));
147                     String key = main.getProperty("STOP.KEY", null);
148                     main.stop(port,key);
149                     return;
150                 }
151                 
152                 if (arg.equalsIgnoreCase("--version")||arg.equalsIgnoreCase("-v")||arg.equalsIgnoreCase("-info"))
153                 {
154                     arguments.remove(i--);
155                     main._showVersions=true;
156                 }
157 
158                 if (arg.indexOf('=')>=0)
159                 {
160                     arguments.remove(i--);
161                     String[] assign=arg.split("=",2);
162                     
163                     if (assign.length==2)
164                         main.setProperty(assign[0],assign[1]);
165                     else
166                         main.setProperty(assign[0],null);
167                 }
168             }
169             
170             DEBUG=Boolean.parseBoolean(main.getProperty("DEBUG","false"));
171             main.start(arguments.toArray(new String[arguments.size()]));        
172             
173         }
174         catch (Exception e)
175         {
176             e.printStackTrace();
177             usage();
178         }
179     }
180 
181     private String getSystemProperty(String name)
182     {
183         if ("version".equalsIgnoreCase(name))
184             return _version;
185         if (_properties.containsKey(name))
186             return _properties.get(name);
187         return System.getProperty(name);
188     }
189     
190     private String getProperty(String name)
191     {
192         if ("version".equalsIgnoreCase(name))
193             return _version;
194         
195         return _properties.get(name);
196     }
197     
198     private String getProperty(String name, String dftValue)
199     {
200         if (_properties.containsKey(name))
201             return _properties.get(name);
202         return dftValue;
203     }
204 
205     private void setProperty(String name, String value)
206     {
207         _properties.put(name,value);
208     }
209 
210     private static void usage()
211     {
212         System.err.println("Usage: java -jar start.jar [--help|--stop|--version] [OPTIONS=option,...] [name=value ...] [config ...]");        
213         System.exit(1);
214     }
215 
216     static File getDirectory(String name)
217     {
218         try
219         {
220             if (name!=null)
221             {
222                 File dir=new File(name).getCanonicalFile();
223                 if (dir.isDirectory())
224                 {
225                     return dir;
226                 }
227             }
228         }
229         catch (IOException e)
230         {
231         }
232         return null;
233     }
234 
235     boolean isAvailable(String classname)
236     {
237         try
238         {
239             Class.forName(classname);
240             return true;
241         }
242         catch (NoClassDefFoundError e)
243         {
244             if (DEBUG)
245                 System.err.println(e);
246         }
247         catch (ClassNotFoundException e)
248         {            
249             if (DEBUG)
250                 System.err.println(e);
251         }
252         ClassLoader loader=_classpath.getClassLoader();
253         try
254         {
255             loader.loadClass(classname);
256             return true;
257         }
258         catch (NoClassDefFoundError e)
259         {
260             if (DEBUG)
261                 System.err.println(e);
262         }
263         catch (ClassNotFoundException e)
264         {
265             if (DEBUG)
266                 System.err.println(e);
267         }
268         return false;
269     }
270 
271     public void invokeMain(ClassLoader classloader, String classname, String[] args) throws IllegalAccessException, InvocationTargetException,
272             NoSuchMethodException, ClassNotFoundException
273     {
274         Class invoked_class=null;
275         
276         try
277         {
278             invoked_class=classloader.loadClass(classname);
279         }
280         catch(ClassNotFoundException e)
281         {
282             //ignored
283         }
284         
285         if (DEBUG || _showVersions || invoked_class==null)
286         {
287             if (invoked_class==null)
288                 System.err.println("ClassNotFound: "+classname);
289             else
290                 System.err.println(classname+" "+invoked_class.getPackage().getImplementationVersion());
291             File[] elements = _classpath.getElements();
292             for (int i=0;i<elements.length;i++)
293                 System.err.println("  "+elements[i].getAbsolutePath());
294             if (_showVersions || invoked_class==null)
295             {
296                 System.err.println("OPTIONS: "+_options);
297 	        usage();
298             }
299         }
300 
301         Class[] method_param_types=new Class[1];
302         method_param_types[0]=args.getClass();
303         Method main=null;
304         main=invoked_class.getDeclaredMethod("main",method_param_types);
305         Object[] method_params=new Object[1];
306         method_params[0]=args;
307 
308         main.invoke(null,method_params);
309     }
310 
311     /* ------------------------------------------------------------ */
312     String expand(String s)
313     {
314         int i1=0;
315         int i2=0;
316         while (s!=null)
317         {
318             i1=s.indexOf("$(");
319             if (i1<0)
320                 break;
321             i2=s.indexOf(")",i1+2);
322             if (i2<0)
323                 break;
324             String name=s.substring(i1+2,i2);
325             String property=getSystemProperty(name);
326             s=s.substring(0,i1)+property+s.substring(i2+1);
327         }
328         
329         i1=0;
330         i2=0;
331         while (s!=null)
332         {
333             i1=s.indexOf("${");
334             if (i1<0)
335                 break;
336             i2=s.indexOf("}",i1+2);
337             if (i2<0)
338                 break;
339             String name=s.substring(i1+2,i2);
340             String property=getProperty(name);
341             s=s.substring(0,i1)+property+s.substring(i2+1);
342         }
343         
344         return s;
345     }
346 
347     /* ------------------------------------------------------------ */
348     void configure(InputStream config, int nargs) throws Exception
349     {
350         BufferedReader cfg=new BufferedReader(new InputStreamReader(config,"ISO-8859-1"));
351         Version java_version=new Version(System.getProperty("java.version"));
352         Version ver=new Version();
353         // JAR's already processed
354         Set<String> done=new HashSet<String>();
355         
356         // Initial classpath
357         String classpath=System.getProperty("CLASSPATH");
358         if (classpath!=null)
359         {
360             StringTokenizer tok=new StringTokenizer(classpath,File.pathSeparator);
361             while (tok.hasMoreTokens())
362                 _classpath.addComponent(tok.nextToken());
363         }
364 
365         List<String> section=null;
366         String o=getProperty("OPTIONS","default");
367         _activeOptions.addAll(Arrays.asList((o.toString()+",*").split("[ ,]")));
368         List<String> unsatisfied_options = new ArrayList<String>( _activeOptions );
369         
370         // Handle line by line
371         String line=null;
372         while (true)
373         {
374             line=cfg.readLine();
375             if (line==null)
376                 break;
377             String trim=line.trim();
378             if (trim.length()==0||trim.startsWith("#"))
379                 continue;
380             
381             // handle options
382             if (trim.startsWith("[") && trim.endsWith("]"))
383             {
384                 section = Arrays.asList(trim.substring(1,trim.length()-1).split("[ ,]"));  
385                 _options.addAll(section);
386             }
387             
388             if (section!=null && Collections.disjoint(section,_activeOptions))
389                 continue;
390             if (section!=null)
391                 unsatisfied_options.removeAll(section);
392             try
393             {
394                 StringTokenizer st=new StringTokenizer(line);
395                 String subject=st.nextToken();
396                 boolean expression=true;
397                 boolean not=false;
398                 String condition=null;
399                 // Evaluate all conditions
400                 while (st.hasMoreTokens())
401                 {
402                     condition=st.nextToken();
403                     if (condition.equalsIgnoreCase("!"))
404                     {
405                         not=true;
406                         continue;
407                     }
408                     if (condition.equalsIgnoreCase("OR"))
409                     {
410                         if (expression)
411                             break;
412                         expression=true;
413                         continue;
414                     }
415                     if (condition.equalsIgnoreCase("AND"))
416                     {
417                         if (!expression)
418                             break;
419                         continue;
420                     }
421                     boolean eval=true;
422                     if (condition.equals("true")||condition.equals("always"))
423                     {
424                         eval=true;
425                     }
426                     else if (condition.equals("false")||condition.equals("never"))
427                     {
428                         eval=false;
429                     }
430                     else if (condition.equals("available"))
431                     {
432                         String class_to_check=st.nextToken();
433                         eval=isAvailable(class_to_check);
434                     }
435                     else if (condition.equals("exists"))
436                     {
437                         try
438                         {
439                             eval=false;
440                             File file=new File(expand(st.nextToken()));
441                             eval=file.exists();
442                         }
443                         catch (Exception e)
444                         {
445                             if (DEBUG)
446                                 e.printStackTrace();
447                         }
448                     }
449                     else if (condition.equals("property"))
450                     {
451                         String property=getProperty(st.nextToken());
452                         eval=property!=null&&property.length()>0;
453                     }
454                     else if (condition.equals("system"))
455                     {
456                         String property=System.getProperty(st.nextToken());
457                         eval=property!=null&&property.length()>0;
458                     }
459                     else if (condition.equals("java"))
460                     {
461                         String operator=st.nextToken();
462                         String version=st.nextToken();
463                         ver.parse(version);
464                         eval=(operator.equals("<")&&java_version.compare(ver)<0)||(operator.equals(">")&&java_version.compare(ver)>0)
465                                 ||(operator.equals("<=")&&java_version.compare(ver)<=0)||(operator.equals("=<")&&java_version.compare(ver)<=0)
466                                 ||(operator.equals("=>")&&java_version.compare(ver)>=0)||(operator.equals(">=")&&java_version.compare(ver)>=0)
467                                 ||(operator.equals("==")&&java_version.compare(ver)==0)||(operator.equals("!=")&&java_version.compare(ver)!=0);
468                     }
469                     else if (condition.equals("nargs"))
470                     {
471                         String operator=st.nextToken();
472                         int number=Integer.parseInt(st.nextToken());
473                         eval=(operator.equals("<")&&nargs<number)||(operator.equals(">")&&nargs>number)||(operator.equals("<=")&&nargs<=number)
474                                 ||(operator.equals("=<")&&nargs<=number)||(operator.equals("=>")&&nargs>=number)||(operator.equals(">=")&&nargs>=number)
475                                 ||(operator.equals("==")&&nargs==number)||(operator.equals("!=")&&nargs!=number);
476                     }
477                     else
478                     {
479                         System.err.println("ERROR: Unknown condition: "+condition);
480                         eval=false;
481                     }
482                     expression&=not?!eval:eval;
483                     not=false;
484                 }
485                 String file=expand(subject);
486                 
487                 if (DEBUG)
488                     System.err.println((expression?"T ":"F ")+line);
489                 if (!expression)
490                 {
491                     done.add(file);
492                     continue;
493                 }
494                 
495                 // Handle setting of start property
496                 if (subject.indexOf("~=")>0)
497                 {
498                     int i=file.indexOf("~=");
499                     String property=file.substring(0,i);
500                     String value=fixPath(file.substring(i+2));
501                     if (DEBUG)
502                         System.err.println("  "+property+"~="+value);
503                     setProperty(property,value);
504                 }
505                 else
506                 // Handle setting of start property with canonical path
507                 if (subject.indexOf("/=")>0)
508                 {
509                     int i=file.indexOf("/=");
510                     String property=file.substring(0,i);
511                     String value=fixPath(file.substring(i+2));
512                     String canonical=new File(value).getCanonicalPath();
513                     if (DEBUG)
514                         System.err.println("  "+property+"/="+value+"=="+canonical);
515                     setProperty(property,canonical);
516                 }
517                 else
518                 // Handle setting of system property
519                 if (subject.indexOf("=")>0)
520                 {
521                     int i=file.indexOf("=");
522                     String property=file.substring(0,i);
523                     String value=fixPath(file.substring(i+1));
524                     if (DEBUG)
525                         System.err.println("  "+property+"="+value);
526                     System.setProperty(property,value);
527                 }
528                 else
529                 // Handle adding all unconsidered jar and zip file
530                 if (subject.endsWith("/*"))
531                 {
532                     // directory of JAR files - only add jars and zips
533                     // within the directory
534                     File dir=new File(fixPath(file.substring(0,file.length()-1)));
535                     addJars(dir,done,false);
536                 }
537                 else
538                 // Handle recursive add of all unconsidered jar and zip files
539                 if (subject.endsWith("/**"))
540                 {
541                     //directory hierarchy of jar files - recursively add all
542                     //jars and zips in the hierarchy
543                     File dir=new File(fixPath(file.substring(0,file.length()-2)));
544                     addJars(dir,done,true);
545                 }
546                 else
547                 // Handle adding raw classpath directory to classpath
548                 if (subject.endsWith("/"))
549                 {
550                     // class directory
551                     File cd=new File(fixPath(file));
552                     String d=cd.getCanonicalPath();
553                     if (!done.contains(d))
554                     {
555                         done.add(d);
556                         boolean added=_classpath.addComponent(d);
557                         if (DEBUG)
558                             System.err.println((added?"  CLASSPATH+=":"  !")+d);
559                     }
560                 }
561                 else
562                 // Handle adding xml configuration
563                 if (subject.toLowerCase().endsWith(".xml"))
564                 {
565                     // Config file
566                     File f=new File(fixPath(file));
567                     if (f.exists())
568                         _xml.add(f.getCanonicalPath());
569                     if (DEBUG)
570                         System.err.println("  ARGS+="+f);
571                 }
572                 else
573                 // Handle setting main class to execute
574                 if (subject.toLowerCase().endsWith(".class"))
575                 {
576                     // Class
577                     String cn=expand(subject.substring(0,subject.length()-6));
578                     if (cn!=null&&cn.length()>0)
579                     {
580                         if (DEBUG)
581                             System.err.println("  CLASS="+cn);
582                         _classname=cn;
583                     }
584                 }
585                 else
586                 // Handle adding raw claspath entry
587                 if (subject.toLowerCase().endsWith(".path"))
588                 {
589                     //classpath (jetty.class.path?) to add to runtime classpath
590                     String cn=expand(subject.substring(0,subject.length()-5));
591                     if (cn!=null&&cn.length()>0)
592                     {
593                         if (DEBUG)
594                             System.err.println("  PATH="+cn);
595                         _classpath.addClasspath(cn);
596                     }                  
597                 }
598                 else
599                 // Handle adding Security policy
600                 if (subject.toLowerCase().endsWith(".policy"))
601                 {
602                     //policy file to parse
603                     String cn=expand(subject.substring(0,subject.length()));
604                     if (cn!=null&&cn.length()>0)
605                     {
606                         if (DEBUG)
607                             System.err.println("  POLICY="+cn);
608                         _policies.add(fixPath(cn));
609                     }                  
610                 }
611                 else
612                 {
613                     // single JAR file
614                     File f=new File(fixPath(file));
615                     if(f.exists())
616                     {
617                         String d=f.getCanonicalPath();
618                         if (!done.contains(d))
619                         {
620                             done.add(d);
621                             boolean added=_classpath.addComponent(d);
622                             if (!added)
623                             {
624                                 added=_classpath.addClasspath(expand(subject));
625                                 if (DEBUG)
626                                     System.err.println((added?"  CLASSPATH+=":"  !")+d);
627                             }
628                             else if (DEBUG)
629                                 System.err.println((added?"  CLASSPATH+=":"  !")+d);
630                         }
631                     }
632                 }
633             }
634             catch (Exception e)
635             {
636                 System.err.println("on line: '"+line+"'");
637                 e.printStackTrace();
638             }
639         }
640 
641         if (unsatisfied_options!=null && unsatisfied_options.size()>0)
642         {
643             System.err.println("Unresolved options: "+unsatisfied_options);
644         }
645     }
646     
647     private String fixPath(String path)
648     {
649     	return path.replace('/',File.separatorChar);
650     }
651 
652     /* ------------------------------------------------------------ */
653     public void start(String[] args)
654     {
655         // set up classpath:
656         InputStream cpcfg=null;
657         try
658         {
659             int port = Integer.parseInt(getProperty("STOP.PORT","-1"));
660             String key = getProperty("STOP.KEY", null);
661             
662             Monitor.monitor(port,key);
663 
664             String config=getProperty("START","org/eclipse/jetty/start/start.config");
665             if (DEBUG)
666             {
667                 System.err.println("config="+config);
668                 System.err.println("properties="+_properties);
669             }
670             cpcfg=getClass().getClassLoader().getResourceAsStream(config);
671             if (cpcfg==null)
672                 cpcfg=new FileInputStream(config);
673             
674             configure(cpcfg,args.length);
675             
676             String jetty_home=System.getProperty("jetty.home");
677             if (jetty_home!=null)
678             {
679                 File file=new File(jetty_home);
680                 String canonical=file.getCanonicalPath();
681                 System.setProperty("jetty.home",canonical);
682             }
683             
684         }
685         catch (Exception e)
686         {
687             e.printStackTrace();
688             System.exit(1);
689         }
690         finally
691         {
692             try
693             {
694                 cpcfg.close();
695             }
696             catch (Exception e)
697             {
698                 e.printStackTrace();
699             }
700         }
701         // okay, classpath complete.
702         System.setProperty("java.class.path",_classpath.toString());
703         ClassLoader cl=_classpath.getClassLoader();
704         if (DEBUG)
705         {
706             System.err.println("java.class.path="+System.getProperty("java.class.path"));
707             System.err.println("jetty.home="+System.getProperty("jetty.home"));
708             System.err.println("java.io.tmpdir="+System.getProperty("java.io.tmpdir"));
709             System.err.println("java.class.path="+_classpath);
710             System.err.println("classloader="+cl);
711             System.err.println("classloader.parent="+cl.getParent());
712         }
713         // Invoke main(args) using new classloader.
714         Thread.currentThread().setContextClassLoader(cl);
715         // re-eval the policy now that env is set
716         try
717         {
718         	if ( _activeOptions.contains("secure") )
719         	{
720         	    Class jettyPolicy = cl.loadClass( "org.eclipse.jetty.policy.JettyPolicy" );
721         	    Constructor c = jettyPolicy.getConstructor( new Class[] { Set.class, Map.class } );
722         	    Object policyClass = c.newInstance( _policies, _properties );
723         	    
724         		Policy.setPolicy( (Policy)policyClass );
725         		System.setSecurityManager( new SecurityManager() );
726         	}
727         	else
728         	{
729         		Policy policy=Policy.getPolicy();
730         		if (policy!=null)
731         			policy.refresh();
732         	}
733         }
734         catch (Exception e)
735         {
736             e.printStackTrace();
737         }
738         try
739         {
740             for (int i=0; i<args.length; i++)
741             {
742                 if (args[i]==null)
743                     continue;
744                 _xml.add(args[i]);
745             }
746             args=(String[])_xml.toArray(args);
747             //check for override of start class
748             String mainClass=System.getProperty("jetty.server");
749             if (mainClass!=null)
750                 _classname=mainClass;
751             mainClass=System.getProperty("main.class");
752             if (mainClass!=null)
753                 _classname=mainClass;
754             if (DEBUG)
755                 System.err.println("main.class="+_classname);
756             invokeMain(cl,_classname,args);
757         }
758         catch (Exception e)
759         {
760             e.printStackTrace();
761         }
762     }
763 
764     /**
765      * Stop a running jetty instance.
766      */
767     public void stop(int port,String key)
768     {
769         int _port=port;
770         String _key=key;
771 
772         try
773         {
774             if (_port<=0)
775                 System.err.println("STOP.PORT system property must be specified");
776             if (_key==null)
777             {
778                 _key="";
779                 System.err.println("STOP.KEY system property must be specified");
780                 System.err.println("Using empty key");
781             }
782 
783             Socket s=new Socket(InetAddress.getByName("127.0.0.1"),_port);
784             OutputStream out=s.getOutputStream();
785             out.write((_key+"\r\nstop\r\n").getBytes());
786             out.flush();
787             s.close();
788         }
789         catch (ConnectException e)
790         {
791             System.err.println("ERROR: Not running!");
792         }
793         catch (Exception e)
794         {
795             e.printStackTrace();
796         }
797     }
798 
799     private void addJars(File dir, Set<String> table, boolean recurse) throws IOException
800     {
801         File[] entries=dir.listFiles();
802 
803         for (int i=0; entries!=null&&i<entries.length; i++)
804         {
805             File entry=entries[i];
806 
807             if (entry.isDirectory()&&recurse)
808                 addJars(entry,table,recurse);
809             else
810             {
811                 String name=entry.getName().toLowerCase();
812                 if (name.endsWith(".jar")||name.endsWith(".zip"))
813                 {
814                     String jar=entry.getCanonicalPath();
815                     if (!table.contains(jar))
816                     {
817                         table.add(jar);
818                         boolean added=_classpath.addComponent(jar);
819                         if (DEBUG)
820                             System.err.println((added?"  CLASSPATH+=":"  !")+jar);
821                     }
822                 }
823             }
824         }
825     }
826 }