// ======================================================================== // Copyright (c) 2002 Mort Bay Consulting (Australia) Pty. Ltd. // $Id$ // ======================================================================== /** * This is an adopted version of the corresponding classes shipped * with Jetty. */ package org.exist.start; import java.io.BufferedReader; import java.io.File; 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.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.exist.storage.BrokerPool; /** * @author Jan Hlavaty (hlavac@code.cz) * @author Wolfgang Meier (meier@ifs.tu-darmstadt.de) * @version $Revision$ * <p/> * TODO: * - finish possible jetty.home locations * - use File.toURI.toURL() on JDK 1.4+ * - better handling of errors (i.e. when jetty.home cannot be autodetected...) * - include entries from lib _when needed_ */ public class Main { private String _classname = null; private String _mode = "jetty"; private static Main exist; private boolean _debug = Boolean.getBoolean("exist.start.debug"); // Stores the path to the "start.config" file that's used to configure // the runtime classpath. private String startConfigFileName = ""; // Used to find latest version of jar files that should be added to the // classpath. private final LatestFileResolver jarFileResolver = new LatestFileResolver(); public static void main(String[] args) { try { getMain().run(args); } catch (Exception e) { e.printStackTrace(); } } /** * Singleton Factory Method */ public static Main getMain(){ if (exist==null) exist = new Main(); return exist; } public String getMode() { return this._mode; } private Main() { } public Main(String mode) { this._mode = mode; } 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, Classpath classpath) { try { Class.forName(classname); return true; } catch (ClassNotFoundException e) { //ignore } ClassLoader loader = classpath.getClassLoader(null); try { loader.loadClass(classname); return true; } catch (ClassNotFoundException e) { //ignore } 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); } void configureClasspath(String home, Classpath classpath, InputStream config, String[] args, String mode) { // Any files referenced in start.config that don't exist or cannot be resolved // are placed in this list. List invalidJars = new ArrayList(); try { 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 Hashtable done = new Hashtable(); String line = cfg.readLine(); while (line != null) { try { if ((line.length() > 0) && (!line.startsWith("#"))) { if (_debug) System.err.println(">" + line); StringTokenizer st = new StringTokenizer(line); String subject = st.nextToken(); boolean include_subject = true; String condition = null; while (include_subject && st.hasMoreTokens()) { condition = st.nextToken(); if (condition.equals("never")) { include_subject = false; } else if (condition.equals("always")) { } else if (condition.equals("available")) { String class_to_check = st.nextToken(); include_subject &= isAvailable(class_to_check, classpath); } else if (condition.equals("!available")) { String class_to_check = st.nextToken(); include_subject &= !isAvailable(class_to_check, classpath); } else if (condition.equals("java")) { String operator = st.nextToken(); String version = st.nextToken(); ver.parse(version); include_subject &= (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()); include_subject &= (operator.equals("<") && args.length < number) || (operator.equals(">") && args.length > number) || (operator.equals("<=") && args.length <= number) || (operator.equals("=<") && args.length <= number) || (operator.equals("=>") && args.length >= number) || (operator.equals(">=") && args.length >= number) || (operator.equals("==") && args.length == number) || (operator.equals("!=") && args.length != number); } else if (condition.equals("mode")) { String operator = st.nextToken(); String m = st.nextToken(); include_subject &= (operator.equals("==") && mode.equals(m)) || (operator.equals("!=") && (!mode.equals(m))); } else { System.err.println("ERROR: Unknown condition: " + condition); } } String file = subject.startsWith("/") ? subject.replace('/', File.separatorChar) : home + File.separatorChar + subject.replace('/', File.separatorChar); if (_debug) System.err.println("subject=" + subject + " file=" + file + " condition=" + condition + " include_subject=" + include_subject); // ok, should we include? 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"); } }); if (jars != null) { for (int i = 0; i < jars.length; i++) { String jar = jars[i].getCanonicalPath(); if (!done.containsKey(jar)) { if (include_subject) { done.put(jar, jar); if (classpath.addComponent(jar) && _debug) System.err.println("Adding JAR from directory: " + jar); } } } } } else if (subject.endsWith("/")) { // class directory File cd = new File(file); String d = cd.getCanonicalPath(); if (!done.containsKey(d)) { done.put(d, d); if (include_subject) { if (classpath.addComponent(d) && _debug) System.err.println("Adding directory: " + d); } } } else if (subject.toLowerCase().endsWith(".class")) { // Class _classname = subject.substring(0, subject.length() - 6); } else { // single JAR file String resolvedFile = jarFileResolver.getResolvedFileName(file); File f = new File(resolvedFile); if (include_subject) { if (!f.exists()) { invalidJars.add(f.getAbsolutePath()); } } String d = f.getCanonicalPath(); if (!done.containsKey(d)) { if (include_subject) { done.put(d, d); if (classpath.addComponent(d) && _debug) System.err.println("Adding single JAR: " + d); } } } } } catch (Exception e) { if (_debug) { System.err.println(line); e.printStackTrace(); } } line = cfg.readLine(); } } catch (Exception e) { e.printStackTrace(); } // Print message if any files from start.config were added // to the classpath but they could not be found. if (invalidJars.size() > 0) { Iterator it = invalidJars.iterator(); StringBuilder nonexistentJars = new StringBuilder(); while (it.hasNext()) { String invalidJar = (String) it.next(); nonexistentJars.append(" " + invalidJar + "\n"); } /* System.err.println( "\nWARN: The following JAR file entries from '" + startConfigFileName + "' aren't available (this may NOT be a " + "problem):\n" + nonexistentJars ); */ } } public void run(String[] args) { if (args.length > 0) { if (args[0].equals("client")) { //_classname = "org.exist.client.InteractiveClient"; _classname = "org.exist.client.InteractiveClient"; _mode = "client"; } else if (args[0].equals("standalone")) { _classname = "org.exist.StandaloneServer"; _mode = "standalone"; } else if (args[0].equals("backup")) { _classname = "org.exist.backup.Main"; _mode = "backup"; } else if (args[0].equals("jetty")) { //_classname = "org.mortbay.jetty.Server"; _classname = "org.exist.JettyStart"; _mode = "jetty"; } else if (args[0].equals("shutdown")) { _classname = "org.exist.ServerShutdown"; _mode = "other"; } else { _classname = args[0]; _mode = "other"; } String[] nargs = new String[args.length - 1]; if (args.length > 1) System.arraycopy(args, 1, nargs, 0, args.length - 1); args = nargs; } else { _classname = "org.exist.client.InteractiveClient"; _mode = "client"; } if (_debug) { System.err.println("mode = " + _mode); } File _home_dir = detectHome(); //TODO: more attempts here... if (_home_dir != null) { // if we managed to detect exist.home, store it in system property if (_debug) System.err.println("EXIST_HOME=" + System.getProperty("exist.home")); // DWES #### can this be removed? System.setProperty("exist.home", _home_dir.getPath()); System.setProperty("user.dir", _home_dir.getPath()); // try to find Jetty if (_mode.equals("jetty") | _mode.equals("cluster")) { File _tools_dir = new File(_home_dir.getAbsolutePath() + File.separatorChar + "tools"); if (!_tools_dir.exists()) { System.err.println("ERROR: tools directory not found in " + _home_dir.getAbsolutePath()); return; } String _jetty_dir = null; String _dirs[] = _tools_dir.list(); for (int i = 0; i < _dirs.length; i++) if (_dirs[i].startsWith("jetty")) { _jetty_dir = _dirs[i]; break; } if (_jetty_dir == null) { System.err.println("ERROR: Jetty could not be found in " + _tools_dir.getPath()); return; } System.setProperty("jetty.home", _tools_dir.getAbsolutePath() + File.separatorChar + _jetty_dir); args = new String[]{ System.getProperty("jetty.home") + File.separatorChar + "etc" + File.separatorChar + "jetty.xml"}; } // find log4j.xml String log4j = System.getProperty("log4j.configuration"); if (log4j == null) { log4j = _home_dir.getPath() + File.separatorChar + "log4j.xml"; File lf = new File(log4j); if (lf.canRead()) System.setProperty("log4j.configuration", lf.toURI().toASCIIString()); } // clean up tempdir for Jetty... try { File tmpdir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile(); if (tmpdir.isDirectory()) { System.setProperty("java.io.tmpdir", tmpdir.getPath()); } } catch (IOException e) { } Classpath _classpath = constructClasspath(_home_dir, args); ClassLoader cl = _classpath.getClassLoader(null); Thread.currentThread().setContextClassLoader(cl); if (_debug) System.err.println("TEMPDIR=" + System.getProperty("java.io.tmpdir")); // Invoke org.mortbay.jetty.Server.main(args) using new classloader. try { invokeMain(cl, _classname, args); } catch (Exception e) { e.printStackTrace(); } } else { // if not, warn user System.err.println("ERROR: exist.home cound not be autodetected, bailing out."); System.err.flush(); } } /** */ public File detectHome() { //-------------------- // detect exist.home: //-------------------- // DWES #### use Configuration.getExistHome() ? File _home_dir = getDirectory(System.getProperty("exist.home")); if (_home_dir == null) { // if eXist is deployed as web application, try to find WEB-INF first File webinf = new File("WEB-INF"); if (_debug) System.err.println("trying " + webinf.getAbsolutePath()); if (webinf.exists()) { File jar = new File(webinf.getPath() + File.separatorChar + "lib" + File.separatorChar + "exist.jar"); if (jar.exists()) try { _home_dir = webinf.getCanonicalFile(); } catch (IOException e) { } } } if (_home_dir == null) { // failed: try exist.jar in current directory File jar = new File("exist.jar"); if (_debug) System.err.println("trying " + jar.getAbsolutePath()); if (jar.canRead()) { try { _home_dir = new File(".").getCanonicalFile(); } catch (IOException e) { } } } if (_home_dir == null) { // failed: try ../exist.jar File jar = new File(".." + File.separatorChar + "exist.jar"); if (_debug) System.err.println("trying " + jar.getAbsolutePath()); if (jar.exists()) try { _home_dir = new File("..").getCanonicalFile(); } catch (IOException e) { } } // searching exist.jar failed, try conf.xml to have the configuration // at least if (_home_dir == null) { // try conf.xml in current dir File jar = new File("conf.xml"); if (_debug) System.err.println("trying " + jar.getAbsolutePath()); if (jar.canRead()) { try { _home_dir = new File(".").getCanonicalFile(); } catch (IOException e) { } } } if (_home_dir == null) { // try ../conf.xml File jar = new File(".." + File.separatorChar + "conf.xml"); if (_debug) System.err.println("trying " + jar.getAbsolutePath()); if (jar.exists()) try { _home_dir = new File("..").getCanonicalFile(); } catch (IOException e) { } } return _home_dir; } /** * @param args */ public Classpath constructClasspath(File homeDir, String[] args) { // set up classpath: Classpath _classpath = new Classpath(); // prefill existing paths in classpath_dirs... if (_debug) System.out.println("existing classpath = " + System.getProperty("java.class.path")); _classpath.addClasspath(System.getProperty("java.class.path")); // add JARs from ext and lib // be smart about it try { InputStream cpcfg = null; // start.config can be found in two locations. String configFilePath1 = ""; String configFilePath2 = ""; try { configFilePath1 = homeDir.getPath() + File.separatorChar + "start.config"; cpcfg = new java.io.FileInputStream(configFilePath1); startConfigFileName = configFilePath1; } catch (java.io.FileNotFoundException e) { cpcfg = null; } if (cpcfg == null) { if (_debug) System.err.println("Configuring classpath from default resource"); configFilePath2 = "org/exist/start/start.config"; cpcfg = getClass().getClassLoader() .getResourceAsStream(configFilePath2); startConfigFileName = configFilePath2; } if (cpcfg == null) { throw new RuntimeException( "start.config not found at " + configFilePath1 + " or " + configFilePath2 + ", Bailing out." ); } if (_debug) { System.err.println( "Configuring classpath from: " + startConfigFileName ); } configureClasspath(homeDir.getPath(), _classpath, cpcfg, args, _mode); cpcfg.close(); } catch (IOException e) { e.printStackTrace(); } // try to find javac and add it in classpaths String java_home = System.getProperty("java.home"); if (java_home != null) { File jdk_home = null; try { jdk_home = new File(java_home).getParentFile().getCanonicalFile(); } catch (IOException e) { } if (jdk_home != null) { File tools_jar_file = null; try { tools_jar_file = new File(jdk_home, "lib" + File.separator + "tools.jar") .getCanonicalFile(); } catch (IOException e) { } if ((tools_jar_file != null) && tools_jar_file.isFile()) { // OK, found tools.jar in java.home/../lib // add it in _classpath.addComponent(tools_jar_file); if (_debug) System.err.println("JAVAC = " + tools_jar_file); } } } // okay, classpath complete. System.setProperty("java.class.path", _classpath.toString()); if (_debug) System.err.println("CLASSPATH=" + _classpath.toString()); return _classpath; } public void shutdown() { BrokerPool.stopAll(false); } }