/* * eXist Open Source Native XML Database * Copyright (C) 2001, Wolfgang M. Meier (meier@ifs.tu-darmstadt.de) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id$ */ package org.exist; import java.io.IOException; import java.util.Enumeration; import java.util.Observer; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; import org.apache.log4j.Logger; import org.exist.cluster.ClusterComunication; import org.exist.cluster.ClusterException; import org.exist.storage.BrokerPool; import org.exist.util.Configuration; import org.exist.util.SingleInstanceConfiguration; import org.exist.validation.XmlLibraryChecker; import org.exist.xmldb.DatabaseImpl; import org.exist.xmldb.ShutdownListener; import org.exist.xquery.functions.system.GetVersion; import org.mortbay.http.HttpContext; import org.mortbay.http.HttpListener; import org.mortbay.jetty.Server; import org.mortbay.util.MultiException; import org.xmldb.api.DatabaseManager; import org.xmldb.api.base.Database; /** * This class provides a main method to start Jetty with eXist. It registers shutdown * handlers to cleanly shut down the database and the webserver. * If database is NATIVE-CLUSTER, Clustercomunication is configured and started. * * @author wolf */ public class JettyStart { protected static final Logger logger = Logger.getLogger(JettyStart.class); public static void main(String[] args) { JettyStart start = new JettyStart(); start.run(args, null); } public JettyStart() { // Additional checks XML libs @@@@ XmlLibraryChecker.check(); } public void run(String[] args, Observer observer) { if (args.length == 0) { logger.info("No configuration file specified!"); return; } String shutdownHookOption = System.getProperty("exist.register-shutdown-hook", "true"); boolean registerShutdownHook = shutdownHookOption.equals("true"); Properties sysProperties = new Properties(); try { sysProperties.load(GetVersion.class.getClassLoader().getResourceAsStream("org/exist/system.properties")); } catch (IOException e) { e.printStackTrace(); } // configure database logger.info("Configuring eXist from " + SingleInstanceConfiguration.getPath()); logger.info(""); logger.info("Running with Java "+ System.getProperty("java.version", "(unknown java.version)") + " [" + System.getProperty("java.vendor", "(unknown java.vendor)") + " (" + System.getProperty("java.vm.name", "(unknown java.vm.name)") + ") in " + System.getProperty("java.home", "(unknown java.home)") +"]"); logger.info(""); String msg; msg = "[eXist Version : " + sysProperties.get("product-version") + "]"; logger.info(msg); msg = "[eXist Build : " + sysProperties.get("product-build") + "]"; logger.info(msg); msg = "[eXist Home : " + System.getProperty("exist.home") + "]"; logger.info(msg); msg = "[SVN Revision : " + sysProperties.get("svn-revision") + "]"; logger.info(msg); msg = "[Operating System : " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch") + "]"; logger.info(msg); msg = "[jetty.home : " + System.getProperty("jetty.home") + "]"; logger.info(msg); msg = "[log4j.configuration : " + System.getProperty("log4j.configuration") + "]"; logger.info(msg); try { // we register our own shutdown hook BrokerPool.setRegisterShutdownHook(false); // configure the database instance SingleInstanceConfiguration config; if (args.length == 2) config = new SingleInstanceConfiguration(args[1]); else config = new SingleInstanceConfiguration(); if (observer != null) BrokerPool.registerStatusObserver(observer); BrokerPool.configure(1, 5, config); // register the XMLDB driver Database xmldb = new DatabaseImpl(); xmldb.setProperty("create-database", "false"); DatabaseManager.registerDatabase(xmldb); configureCluster(config); } catch (Exception e) { logger.error("configuration error: ", e); e.printStackTrace(); return; } // start Jetty final Server server; int port = 8080; try { server = new Server(args[0]); BrokerPool.getInstance().registerShutdownListener(new ShutdownListenerImpl(server)); server.start(); HttpListener[] listeners = server.getListeners(); StringBuilder ports = new StringBuilder(); if (listeners.length > 0) { for (HttpListener listener : listeners) { port = listener.getPort(); ports.append(" "+port); } } else { ports.append(" "+port); } HttpContext[] contexts = server.getContexts(); logger.info("----------------------------------------------------------------"); logger.info("eXist-db has started on port" + ports + ". Configured contexts:"); for (int i = 0; i < contexts.length; i++) { logger.info("http://localhost:" + port + contexts[i].getContextPath()); } logger.info("----------------------------------------------------------------"); if (registerShutdownHook) { // register a shutdown hook for the server Thread hook = new Thread() { public void run() { setName("Shutdown"); BrokerPool.stopAll(true); try { server.stop(); } catch (InterruptedException e) { } try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } }; Runtime.getRuntime().addShutdownHook(hook); } } catch (MultiException e) { boolean hasBindException=false; for(Object t : e.getExceptions()){ if(t instanceof java.net.BindException){ hasBindException=true; logger.info("----------------------------------------------------------"); logger.info("ERROR: Could not bind to port because " + ((Exception) t).getMessage()); logger.info(t.toString()); logger.info("----------------------------------------------------------"); } } // If it is another error, print stacktrace if(!hasBindException){ e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } } public void shutdown() { BrokerPool.stopAll(false); } /** * This class gets called after the database received a shutdown request. * * @author wolf */ private static class ShutdownListenerImpl implements ShutdownListener { private Server server; public ShutdownListenerImpl(Server server) { this.server = server; } public void shutdown(String dbname, int remainingInstances) { logger.info("Database shutdown: stopping server in 1sec ..."); if (remainingInstances == 0) { // give the webserver a 1s chance to complete open requests Timer timer = new Timer(); timer.schedule(new TimerTask() { public void run() { try { // stop the server server.stop(); ClusterComunication cluster = ClusterComunication.getInstance(); if(cluster!=null){ cluster.stop(); } } catch (InterruptedException e) { e.printStackTrace(); } System.exit(0); } }, 1000); } } } private void configureCluster(Configuration c) throws ClusterException { String database = (String)c.getProperty("database"); if(! database.equalsIgnoreCase("NATIVE_CLUSTER")) return; ClusterComunication.configure(c); } }