Main.java {{{ #!java package start; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.Policy; import java.util.ArrayList; import java.util.Hashtable; import java.util.StringTokenizer; /*-------------------------------------------*/ /** * Main start class. This class is intended to be the main class listed in the * MANIFEST.MF of the start.jar archive. It allows an application to be started * with the command "java -jar start.jar". The behaviour of Main is controlled * by the "org/mortbay/start/start.config" file obtained as a resource or file. * This can be overridden with the START system property. The format of each * line in this file is: * *
 * 
 * SUBJECT [ [!] CONDITION [AND|OR] ]*
 * 
 * 
* * where SUBJECT: * *
 * 
 * ends with ".class" is the Main class to run. ends with ".xml" is a configuration file for the
 * command line ends with "/" is a directory from which add all jar and zip files from. ends with
 * "/*" is a directory from which add all unconsidered jar and zip files from. Containing = are
 * used to assign system properties. all other subjects are treated as files to be added to the
 * classpath.
 * 
 * 
* * Subjects may include system properties with $(propertyname) syntax. File * subjects starting with "/" are considered absolute, all others are relative * to the home directory. *

* CONDITION is one of: * *

 * 
 * always never available package.class java OPERATOR n.n nargs OPERATOR n OPERATOR := one of "
 * <",">"," <=",">=","==","!="
 * 
 * 
* * CONTITIONS can be combined with AND OR or !, with AND being the assume * operator for a list of CONDITIONS. Classpath operations are evaluated on the * fly, so once a class or jar is added to the classpath, subsequent available * conditions will see that class. The system parameter CLASSPATH, if set is * given to the start classloader before any paths from the configuration file. * Programs started with start.jar may be stopped with the stop.jar, which * connects via a local port to stop the server. The default port can be set * with the STOP.PORT system property (a port of < 0 disables the stop * mechanism). If the STOP.KEY system property is set, then a random key is * generated and written to stdout. This key must be passed to the stop.jar. * * @author Jan Hlavaty (hlavac@code.cz) * @author Greg Wilkins * @version $Revision: 1.37 $ */ @SuppressWarnings("unchecked") public class Main { static boolean _debug = System.getProperty("DEBUG", null) != null; private String _classname = null; private Classpath _classpath = new Classpath(); private String _config = System.getProperty("START", "start/start.config"); private ArrayList _xml = new ArrayList(); public static void main(String[] args) { try { new Main().start(args); } catch (Exception e) { e.printStackTrace(); } } static File getDirectory(String name) { try { if (name != null) { File dir = new File(name).getCanonicalFile(); if (dir.isDirectory()) { return dir; } } } catch (IOException e) { } return null; } boolean isAvailable(String classname) { try { Class.forName(classname); return true; } catch (NoClassDefFoundError e) { } catch (ClassNotFoundException e) { } ClassLoader loader = _classpath.getClassLoader(); try { loader.loadClass(classname); return true; } catch (NoClassDefFoundError e) { } catch (ClassNotFoundException e) { } return false; } public static void invokeMain(ClassLoader classloader, String classname, String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { Class invoked_class = null; invoked_class = classloader.loadClass(classname); Class[] method_param_types = new Class[1]; method_param_types[0] = args.getClass(); Method main = null; main = invoked_class.getDeclaredMethod("main", method_param_types); Object[] method_params = new Object[1]; method_params[0] = args; main.invoke(null, method_params); } /* ------------------------------------------------------------ */ String expand(String s) { int i1 = 0; int i2 = 0; while (s != null) { i1 = s.indexOf("$(", i2); if (i1 < 0) break; i2 = s.indexOf(")", i1 + 2); if (i2 < 0) break; String property = System.getProperty(s.substring(i1 + 2, i2), ""); s = s.substring(0, i1) + property + s.substring(i2 + 1); } return s; } /* ------------------------------------------------------------ */ void configure(InputStream config, int nargs) throws Exception { BufferedReader cfg = new BufferedReader(new InputStreamReader(config, "ISO-8859-1")); Version java_version = new Version(System.getProperty("java.version")); Version ver = new Version(); // JAR's already processed java.util.Hashtable done = new Hashtable(); // Initial classpath String classpath = System.getProperty("CLASSPATH"); if (classpath != null) { StringTokenizer tok = new StringTokenizer(classpath, File.pathSeparator); while (tok.hasMoreTokens()) _classpath.addComponent(tok.nextToken()); } // Handle line by line String line = null; while (true) { line = cfg.readLine(); if (line == null) break; if (line.length() == 0 || line.startsWith("#")) continue; try { StringTokenizer st = new StringTokenizer(line); String subject = st.nextToken(); subject = expand(subject); boolean expression = true; boolean not = false; String condition = null; // Evaluate all conditions while (st.hasMoreTokens()) { condition = st.nextToken(); if (condition.equalsIgnoreCase("!")) { not = true; continue; } if (condition.equalsIgnoreCase("OR")) { if (expression) break; expression = true; continue; } if (condition.equalsIgnoreCase("AND")) { if (!expression) break; continue; } boolean eval = true; if (condition.equals("true") || condition.equals("always")) { eval = true; } else if (condition.equals("false") || condition.equals("never")) { eval = false; } else if (condition.equals("available")) { String class_to_check = st.nextToken(); eval = isAvailable(class_to_check); } else if (condition.equals("exists")) { try { eval = false; File file = new File(expand(st.nextToken())); eval = file.exists(); } catch (Exception e) { if (_debug) e.printStackTrace(); } } else if (condition.equals("property")) { String property = System.getProperty(st.nextToken()); eval = property != null && property.length() > 0; } else if (condition.equals("java")) { String operator = st.nextToken(); String version = st.nextToken(); ver.parse(version); eval = (operator.equals("<") && java_version .compare(ver) < 0) || (operator.equals(">") && java_version .compare(ver) > 0) || (operator.equals("<=") && java_version .compare(ver) <= 0) || (operator.equals("=<") && java_version .compare(ver) <= 0) || (operator.equals("=>") && java_version .compare(ver) >= 0) || (operator.equals(">=") && java_version .compare(ver) >= 0) || (operator.equals("==") && java_version .compare(ver) == 0) || (operator.equals("!=") && java_version .compare(ver) != 0); } else if (condition.equals("nargs")) { String operator = st.nextToken(); int number = Integer.parseInt(st.nextToken()); eval = (operator.equals("<") && nargs < number) || (operator.equals(">") && nargs > number) || (operator.equals("<=") && nargs <= number) || (operator.equals("=<") && nargs <= number) || (operator.equals("=>") && nargs >= number) || (operator.equals(">=") && nargs >= number) || (operator.equals("==") && nargs == number) || (operator.equals("!=") && nargs != number); } else { System.err.println("ERROR: Unknown condition: " + condition); eval = false; } expression &= not ? !eval : eval; not = false; } String file = subject.replace('/', File.separatorChar); if (_debug) System.err.println((expression ? "T " : "F ") + line + " subject=" + subject); if (!expression) { done.put(file, file); continue; } // Handle the subject if (subject.indexOf("=") > 0) { int i = file.indexOf("="); String property = file.substring(0, i); String value = file.substring(i + 1); if (_debug) System.err.println(" " + property + "=" + value); System.setProperty(property, value); } else if (subject.endsWith("/*")) { // directory of JAR files File extdir = new File(file.substring(0, file.length() - 1)); File[] jars = extdir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { String namelc = name.toLowerCase(); return namelc.endsWith(".jar") || name.endsWith(".zip"); } }); for (int i = 0; jars != null && i < jars.length; i++) { String jar = jars[i].getCanonicalPath(); if (!done.containsKey(jar)) { done.put(jar, jar); boolean added = _classpath.addComponent(jar); if (_debug) System.err.println((added ? " CLASSPATH+=" : " !") + jar); } } } else if (subject.endsWith("/")) { // class directory File cd = new File(file); String d = cd.getCanonicalPath(); if (!done.containsKey(d)) { done.put(d, d); boolean added = _classpath.addComponent(d); if (_debug) System.err .println((added ? " CLASSPATH+=" : " !") + d); } } else if (subject.toLowerCase().endsWith(".xml")) { // Config file File f = new File(file); if (f.exists()) _xml.add(f.getCanonicalPath()); if (_debug) System.err.println(" ARGS+=" + f); } else if (subject.toLowerCase().endsWith(".class")) { // Class String cn = expand(subject.substring(0, subject.length() - 6)); if (cn != null && cn.length() > 0) { if (_debug) System.err.println(" CLASS=" + cn); _classname = cn; } } else if (subject != null && subject.length() > 0) { // single JAR file File f = new File(file); String d = f.getCanonicalPath(); if (!done.containsKey(d)) { done.put(d, d); boolean added = _classpath.addComponent(d); if (!added) { added = _classpath.addClasspath(expand(subject)); if (_debug) System.err.println((added ? " CLASSPATH+=" : " !") + d); } else if (_debug) System.err .println((added ? " CLASSPATH+=" : " !") + d); } } } catch (Exception e) { System.err.println("on line: '" + line + "'"); e.printStackTrace(); } } } /* ------------------------------------------------------------ */ public void start(String[] args) { ArrayList al = new ArrayList(); for (int i = 0; i < args.length; i++) { if (args[i] == null) continue; if (args[i].startsWith("-")) { System.err .println("Usage: java [-DDEBUG] [-DSTART=start.config] [-Dmain.class=org.MyMain] -jar start.jar [--help] [config ...]"); System.exit(1); } else al.add(args[i]); } args = (String[]) al.toArray(new String[al.size()]); // set up classpath: InputStream cpcfg = null; try { Monitor.monitor(); cpcfg = getClass().getClassLoader().getResourceAsStream(_config); if (_debug) System.err.println("config=" + _config); if (cpcfg == null) cpcfg = new FileInputStream(_config); configure(cpcfg, args.length); File file = new File(System.getProperty("jetty.home")); String canonical = file.getCanonicalPath(); System.setProperty("jetty.home", canonical); } catch (Exception e) { e.printStackTrace(); System.exit(1); } finally { try { cpcfg.close(); } catch (Exception e) { e.printStackTrace(); } } // okay, classpath complete. System.setProperty("java.class.path", _classpath.toString()); ClassLoader cl = _classpath.getClassLoader(); if (_debug) { System.err.println("java.class.path=" + System.getProperty("java.class.path")); System.err .println("jetty.home=" + System.getProperty("jetty.home")); System.err.println("java.io.tmpdir=" + System.getProperty("java.io.tmpdir")); System.err.println("java.class.path=" + _classpath); System.err.println("classloader=" + cl); System.err.println("classloader.parent=" + cl.getParent()); } // Invoke main(args) using new classloader. Thread.currentThread().setContextClassLoader(cl); // re-eval the policy now that env is set try { Policy policy = Policy.getPolicy(); if (policy != null) policy.refresh(); } catch (Exception e) { e.printStackTrace(); } try { for (int i = 0; i < args.length; i++) { if (args[i] == null) continue; _xml.add(args[i]); } args = (String[]) _xml.toArray(args); if (_debug) System.err.println("main.class=" + _classname); invokeMain(cl, _classname, args); } catch (Exception e) { e.printStackTrace(); } } } }}}