Package org.exist.jetty

Source Code of org.exist.jetty.JettyStart$ShutdownListenerImpl

/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2014 The eXist-db Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.exist.jetty;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.net.SocketException;
import java.util.Observable;
import java.util.Observer;
import java.util.Timer;
import java.util.TimerTask;

import javax.servlet.Servlet;

import org.apache.log4j.Logger;

import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.xml.XmlConfiguration;

import org.exist.SystemProperties;
import org.exist.storage.BrokerPool;
import org.exist.util.ConfigurationHelper;
import org.exist.util.SingleInstanceConfiguration;
import org.exist.validation.XmlLibraryChecker;
import org.exist.xmldb.DatabaseImpl;
import org.exist.xmldb.ShutdownListener;

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.
*
* @author wolf
*/
public class JettyStart extends Observable implements LifeCycle.Listener {

    protected static final Logger logger = Logger.getLogger(JettyStart.class);

    public static void main(String[] args) {
        final JettyStart start = new JettyStart();
        start.run(args, null);
    }

    public final static String SIGNAL_STARTING = "jetty starting";
    public final static String SIGNAL_STARTED = "jetty started";
    public final static String SIGNAL_ERROR = "error";

    private final static int STATUS_STARTING = 0;
    private final static int STATUS_STARTED = 1;
    private final static int STATUS_STOPPING = 2;
    private final static int STATUS_STOPPED = 3;

    private int status = STATUS_STOPPED;
    private Thread shutdownHook = null;
    private int primaryPort = 8080;

    public JettyStart() {
        // Additional checks XML libs @@@@
        XmlLibraryChecker.check();
    }

    public void run() {
        String jettyProperty = System.getProperty("jetty.home");
        if(jettyProperty==null) {
            final File home = ConfigurationHelper.getExistHome();
            final File jettyHome = new File(new File(home, "tools"), "jetty");
            jettyProperty = jettyHome.getAbsolutePath();
            System.setProperty("jetty.home", jettyProperty);
        }
        final File standaloneFile = new File(new File(jettyProperty, "etc"), "standalone.xml");
        run(new String[]{standaloneFile.getAbsolutePath()}, null);
    }
   
    public void run(String[] args, Observer observer) {
        if (args.length == 0) {
            logger.info("No configuration file specified!");
            return;
        }

        final String shutdownHookOption = System.getProperty("exist.register-shutdown-hook", "true");
        boolean registerShutdownHook = "true".equals(shutdownHookOption);

        if (observer != null) {
            addObserver(observer);
        }

        // configure database
        logger.info("Configuring eXist from " + SingleInstanceConfiguration.getPath());

        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("Running as user '"
                + System.getProperty("user.name", "(unknown user.name)") + "'");

        logger.info("[eXist Version : "
                + SystemProperties.getInstance().getSystemProperty("product-version", "unknown") + "]");
        logger.info("[eXist Build : "
                + SystemProperties.getInstance().getSystemProperty("product-build", "unknown") + "]");
        logger.info("[eXist Home : "
                + SystemProperties.getInstance().getSystemProperty("exist.home", "unknown") + "]");
        logger.info("[Git commmit : "
                + SystemProperties.getInstance().getSystemProperty("git-commit", "unknown") + "]");
       
        logger.info("[Operating System : "
                + System.getProperty("os.name") + " "
                + System.getProperty("os.version") + " "
                + System.getProperty("os.arch") + "]");
       
        logger.info("[jetty.home : "
                + System.getProperty("jetty.home") + "]");
        logger.info("[log4j.configuration : "
                + System.getProperty("log4j.configuration") + "]");

        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
            final Database xmldb = new DatabaseImpl();
            xmldb.setProperty("create-database", "false");
            DatabaseManager.registerDatabase(xmldb);

        } catch (final Exception e) {
            logger.error("configuration error: " + e.getMessage(), e);
            e.printStackTrace();
            return;
        }

        // start Jetty
        final Server server;
        try {
            server = new Server();
            MBeanContainer mBeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
            server.getContainer().addEventListener(mBeanContainer);
            server.addBean(mBeanContainer);
            server.addBean(Log.getLog());

            final InputStream is = new FileInputStream(args[0]);
            final XmlConfiguration configuration = new XmlConfiguration(is);
            configuration.configure(server);
           
            server.setStopAtShutdown(true);
            server.addLifeCycleListener(this);

            BrokerPool.getInstance().registerShutdownListener(new ShutdownListenerImpl(server));
            server.start();

            final Connector[] connectors = server.getConnectors();

            // Construct description of all ports opened.
            final StringBuilder allPorts = new StringBuilder();

            if (connectors.length > 1) {
                // plural s
                allPorts.append("s");
            }

            for(final Connector connector: connectors){
                allPorts.append(" ");
                allPorts.append(connector.getPort());
            }
            if (connectors.length > 0) {
                primaryPort = connectors[0].getPort();
            }

            //TODO: use pluggable interface
            Class<?> openid = null;
            try {
              openid = Class.forName("org.exist.security.realm.openid.AuthenticatorOpenIdServlet");
            } catch (final ClassNotFoundException e) {
                // ignore
      }
           
            Class<?> oauth = null;
            try {
              oauth = Class.forName("org.exist.security.realm.oauth.OAuthServlet");
            } catch (final ClassNotFoundException e) {
                // ignore
      }
           
            //*************************************************************

            logger.info("-----------------------------------------------------");
            logger.info("Server has started on port" + allPorts + ". Configured contexts:");

            final HandlerCollection rootHandler = (HandlerCollection)server.getHandler();
            final Handler[] handlers = rootHandler.getHandlers();
           
            for (final Handler handler: handlers) {
               
                if (handler instanceof ContextHandler) {
                    final ContextHandler contextHandler = (ContextHandler) handler;
                    logger.info("'" + contextHandler.getContextPath() + "'");
                }
             
                //TODO: pluggable in future
                if (openid != null) {
                    if (handler instanceof ServletContextHandler) {
                        final ServletContextHandler contextHandler = (ServletContextHandler) handler;
                        contextHandler.addServlet(new ServletHolder((Class<? extends Servlet>) openid), "/openid");

                        String suffix;
                        if (contextHandler.getContextPath().endsWith("/")) {
                            suffix = "openid";
                        } else {
                            suffix = "/openid";
                        }

                        logger.info("'" + contextHandler.getContextPath() + suffix + "'");
                    }
                }

                if (oauth != null) {
                    if (handler instanceof ServletContextHandler) {
                        final ServletContextHandler contextHandler = (ServletContextHandler) handler;
                        contextHandler.addServlet(new ServletHolder((Class<? extends Servlet>) oauth), "/oauth/*");

                        String suffix;
                        if (contextHandler.getContextPath().endsWith("/")) {
                            suffix = "oauth";
                        } else {
                            suffix = "/oauth";
                        }

                        logger.info("'" + contextHandler.getContextPath() + suffix + "'");
                    }
                }
                //*************************************************************
            }

            logger.info("-----------------------------------------------------");

            if (registerShutdownHook) {
                // register a shutdown hook for the server
                shutdownHook = new Thread() {

                    @Override
                    public void run() {
                        setName("Shutdown");
                        BrokerPool.stopAll(true);
                        if (server.isStopping() || server.isStopped()) {
                            return;
                        }
                       
                        try {
                            server.stop();
                        } catch (final Exception e) {
                            // ignore
                        }
                       
                    }
                };
                Runtime.getRuntime().addShutdownHook(shutdownHook);
            }

            setChanged();
            notifyObservers(SIGNAL_STARTED);
           
        } catch (final MultiException e) {

            // Mute the BindExceptions

            boolean hasBindException = false;
            for (final Object t : e.getThrowables()) {
                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();
            }
            setChanged();
            notifyObservers(SIGNAL_ERROR);
           
        } catch (final SocketException e) {
            logger.info("----------------------------------------------------------");
            logger.info("ERROR: Could not bind to port because " + e.getMessage());
            logger.info(e.toString());
            logger.info("----------------------------------------------------------");
            setChanged();
            notifyObservers(SIGNAL_ERROR);
           
        } catch (final Exception e) {
            e.printStackTrace();
            setChanged();
            notifyObservers(SIGNAL_ERROR);
        }
    }

    public synchronized void shutdown() {
        if (shutdownHook != null) {
            Runtime.getRuntime().removeShutdownHook(shutdownHook);
        }
       
        BrokerPool.stopAll(false);
       
        while (status != STATUS_STOPPED) {
            try {
                wait();
            } catch (final InterruptedException e) {
                // ignore
            }
        }
    }

    /**
     * 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
                final Timer timer = new Timer("jetty shutdown schedule", true);
                timer.schedule(new TimerTask() {
                    public void run() {
                        try {
                            // stop the server
                            server.stop();
                            server.join();
                        } catch (final Exception e) {
                            e.printStackTrace();
                        }
                    }
                }, 1000); // timer.schedule
            }
        }
    }


    public synchronized boolean isStarted() {
        if (status == STATUS_STARTED || status == STATUS_STARTING) {
            return true;
        }
        if (status == STATUS_STOPPED) {
            return false;
        }
        while (status != STATUS_STOPPED) {
            try {
                wait();
            } catch (final InterruptedException e) {
            }
        }
        return false;
    }

    public synchronized void lifeCycleStarting(LifeCycle lifeCycle) {
        logger.info("Jetty server starting...");
        setChanged();
        notifyObservers(SIGNAL_STARTING);
        status = STATUS_STARTING;
        notifyAll();
    }

    public synchronized void lifeCycleStarted(LifeCycle lifeCycle) {
        logger.info("Jetty server started.");
        setChanged();
        notifyObservers(SIGNAL_STARTED);
        status = STATUS_STARTED;
        notifyAll();
    }

    public void lifeCycleFailure(LifeCycle lifeCycle, Throwable throwable) {
    }

    public synchronized void lifeCycleStopping(LifeCycle lifeCycle) {
        logger.info("Jetty server stopping...");
        status = STATUS_STOPPING;
        notifyAll();
    }

    public synchronized void lifeCycleStopped(LifeCycle lifeCycle) {
        logger.info("Jetty server stopped");
        status = STATUS_STOPPED;
        notifyAll();
    }

    public int getPrimaryPort() {
        return primaryPort;
    }

    public void systemInfo() {
      BrokerPool.systemInfo();
    }
}
TOP

Related Classes of org.exist.jetty.JettyStart$ShutdownListenerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.