com.salmonllc.ideTools.Tomcat50Engine.java Source code

Java tutorial

Introduction

Here is the source code for com.salmonllc.ideTools.Tomcat50Engine.java

Source

/*
 * Copyright 1999,2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.salmonllc.ideTools;

import com.salmonllc.util.MessageLog;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import org.apache.catalina.Container;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Server;
import org.apache.catalina.core.StandardServer;
import org.apache.catalina.startup.ClusterRuleSet;
import org.apache.catalina.startup.ContextRuleSet;
import org.apache.catalina.startup.Embedded;
import org.apache.catalina.startup.EngineRuleSet;
import org.apache.catalina.startup.HostRuleSet;
import org.apache.catalina.startup.NamingRuleSet;
import org.apache.catalina.startup.SetAllPropertiesRule;
import org.apache.catalina.util.CatalinaDigester;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.Rule;
import org.apache.tomcat.util.log.SystemLogHandler;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;

/**
 * Startup/Shutdown shell program for Catalina.  The following command line options are recognized: <ul> <li><b>-config {pathname}</b> - Set the pathname of the configuration file to be processed.  If a relative path is specified, it will be interpreted as relative to the directory pathname specified by the "catalina.base" system property.   [conf/server.xml] <li><b>-help</b> - Display usage information. <li><b>-stop</b> - Stop the currently running instance of Catalina. </u> Should do the same thing as Embedded, but using a server.xml file.
 * @author  Craig R. McClanahan
 * @author  Remy Maucherat
 * @version  $Revision: 1 $ $Date: 8/05/04 2:55p $
 */

public class Tomcat50Engine extends Embedded {

    // ----------------------------------------------------- Instance Variables

    /**
     * Pathname to the server configuration file.
     */
    protected String _configFile = "conf/server.xml";

    // XXX Should be moved to embedded
    /**
     * The shared extensions class loader for this server.
     */
    protected ClassLoader _parentClassLoader = Tomcat50Engine.class.getClassLoader();

    /**
     * The server component we are starting or stopping
     */
    protected Server _server = null;

    /**
     * Are we starting a new server?
     */
    protected boolean _starting = false;

    /**
     * Are we stopping an existing server?
     */
    protected boolean _stopping = false;

    /**
     * Use shutdown hook flag.
     */
    protected boolean _useShutdownHook = true;

    /**
     * Shutdown hook.
     */
    protected Thread _shutdownHook = null;

    //Salmon Added
    private Process _browserProcess = null;
    private Tomcat50Bootstrap _bootstrap;
    private Tomcat50ShutdownProperties _shutdown;
    //End Salmon Added

    // ------------------------------------------------------------- Properties

    public void setConfig(String file) {
        _configFile = file;
    }

    public void setConfigFile(String file) {
        _configFile = file;
    }

    public String getConfigFile() {
        return _configFile;
    }

    public void setUseShutdownHook(boolean useShutdownHook) {
        this._useShutdownHook = useShutdownHook;
    }

    public boolean getUseShutdownHook() {
        return _useShutdownHook;
    }

    /**
     * Set the shared extensions class loader.
     *
     * @param parentClassLoader The shared extensions class loader.
     */
    public void setParentClassLoader(ClassLoader parentClassLoader) {

        this._parentClassLoader = parentClassLoader;

    }

    /**
     * Set the server instance we are configuring.
     *
     * @param server The new server
     */
    public void setServer(Server server) {

        this._server = server;

    }

    // ------------------------------------------------------ Protected Methods

    /**
     * Process the specified command line arguments, and return
     * <code>true</code> if we should continue processing; otherwise
     * return <code>false</code>.
     *
     * @param args Command line arguments to process
     */
    protected boolean arguments(String args[]) {

        boolean isConfig = false;

        if (args.length < 1) {
            usage();
            return (false);
        }

        for (int i = 0; i < args.length; i++) {
            if (isConfig) {
                _configFile = args[i];
                isConfig = false;
            } else if (args[i].equals("-config")) {
                isConfig = true;
            } else if (args[i].equals("-debug")) {
                debug = 1;
            } else if (args[i].equals("-nonaming")) {
                setUseNaming(false);
            } else if (args[i].equals("-help")) {
                usage();
                return (false);
            } else if (args[i].equals("start")) {
                _starting = true;
                _stopping = false;
            } else if (args[i].equals("stop")) {
                _starting = false;
                _stopping = true;
            } else {
                usage();
                return (false);
            }
        }

        return (true);

    }

    /**
     * Return a File object representing our configuration file.
     */
    protected File configFile() {

        File file = new File(_configFile);
        if (!file.isAbsolute())
            file = new File(System.getProperty("catalina.base"), _configFile);
        return (file);

    }

    /**
     * Create and configure the Digester we will be using for startup.
     */
    protected Digester createStartDigester() {
        long t1 = System.currentTimeMillis();
        // Initialize the digester
        Digester digester = new CatalinaDigester();
        digester.setValidating(false);
        digester.setClassLoader(StandardServer.class.getClassLoader());

        // Configure the actions we will be using
        digester.addObjectCreate("Server", "org.apache.catalina.core.StandardServer", "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server", "setServer", "org.apache.catalina.Server");

        digester.addObjectCreate("Server/GlobalNamingResources", "org.apache.catalina.deploy.NamingResources");
        digester.addSetProperties("Server/GlobalNamingResources");
        digester.addSetNext("Server/GlobalNamingResources", "setGlobalNamingResources",
                "org.apache.catalina.deploy.NamingResources");

        digester.addObjectCreate("Server/Listener", null, // MUST be specified in the element
                "className");
        digester.addSetProperties("Server/Listener");
        digester.addSetNext("Server/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener");

        digester.addObjectCreate("Server/Service", "org.apache.catalina.core.StandardService", "className");
        digester.addSetProperties("Server/Service");
        digester.addSetNext("Server/Service", "addService", "org.apache.catalina.Service");

        digester.addObjectCreate("Server/Service/Listener", null, // MUST be specified in the element
                "className");
        digester.addSetProperties("Server/Service/Listener");
        digester.addSetNext("Server/Service/Listener", "addLifecycleListener",
                "org.apache.catalina.LifecycleListener");

        digester.addObjectCreate("Server/Service/Connector", "org.apache.coyote.tomcat5.CoyoteConnector",
                "className");
        digester.addRule("Server/Service/Connector", new SetAllPropertiesRule());
        digester.addSetNext("Server/Service/Connector", "addConnector", "org.apache.catalina.Connector");

        digester.addObjectCreate("Server/Service/Connector/Factory",
                "org.apache.coyote.tomcat5.CoyoteServerSocketFactory", "className");
        digester.addSetProperties("Server/Service/Connector/Factory");
        digester.addSetNext("Server/Service/Connector/Factory", "setFactory",
                "org.apache.catalina.net.ServerSocketFactory");

        digester.addObjectCreate("Server/Service/Connector/Listener", null, // MUST be specified in the element
                "className");
        digester.addSetProperties("Server/Service/Connector/Listener");
        digester.addSetNext("Server/Service/Connector/Listener", "addLifecycleListener",
                "org.apache.catalina.LifecycleListener");

        // Add RuleSets for nested elements
        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Default"));
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/DefaultContext/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/Default"));
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/DefaultContext/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
        digester.addRuleSet(new ClusterRuleSet("Server/Service/Engine/Host/Cluster/"));
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));

        // When the 'engine' is found, set the parentClassLoader.
        digester.addRule("Server/Service/Engine", new SetParentClassLoaderRule(_parentClassLoader));

        long t2 = System.currentTimeMillis();
        log.debug("Digester for server.xml created " + (t2 - t1));
        return (digester);

    }

    /**
     * Create and configure the Digester we will be using for shutdown.
     */
    protected Digester createStopDigester() {

        // Initialize the digester
        Digester digester = new Digester();

        // Configure the rules we need for shutting down
        digester.addObjectCreate("Server", "com.salmonllc.ideTools.Tomcat50ShutdownProperties", "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server", "setShutdownProperties", "com.salmonllc.ideTools.Tomcat50ShutdownProperties");

        return (digester);

    }

    public void stopServer(String[] arguments, Tomcat50Bootstrap bootstrap) {

        if (_server == null) {
            // Create and execute our Digester
            Digester digester = createStopDigester();
            digester.setClassLoader(Thread.currentThread().getContextClassLoader());
            File file = configFile();
            try {
                InputSource is = new InputSource("file://" + file.getAbsolutePath());
                FileInputStream fis = new FileInputStream(file);
                is.setByteStream(fis);
                digester.push(this);
                digester.parse(is);
                fis.close();
            } catch (Exception e) {
                System.out.println("Catalina.stop: " + e);
                e.printStackTrace(System.out);
                System.exit(1);
            }
        }

        // Stop the existing server
        try {
            String host = "127.0.0.1";
            int port = 8005;
            String shutdown = "SHUTDOWN";

            if (_shutdown != null) {
                port = _shutdown.getPort();
                shutdown = _shutdown.getShutdown();
            }

            Socket socket = new Socket(host, port);
            OutputStream stream = socket.getOutputStream();

            for (int i = 0; i < shutdown.length(); i++)
                stream.write(shutdown.charAt(i));
            stream.flush();
            stream.close();
            socket.close();
            Thread.sleep(500);
        } catch (Exception e) {
            //System.out.println("Catalina.stop: " + e);
            //e.printStackTrace(System.out);
            //System.exit(1);
        }

        bootstrap.notifyComplete();

    }

    /**
     * Set the <code>catalina.base</code> System property to the current
     * working directory if it has not been set.
     * @deprecated Use initDirs()
     */
    public void setCatalinaBase() {
        initDirs();
    }

    /**
     * Set the <code>catalina.home</code> System property to the current
     * working directory if it has not been set.
     * @deprecated Use initDirs()
     */
    public void setCatalinaHome() {
        initDirs();
    }

    /**
     * Start a new server instance.
     */
    public void load() {
        initDirs();

        // Before digester - it may be needed

        initNaming();

        // Create and execute our Digester
        Digester digester = createStartDigester();
        long t1 = System.currentTimeMillis();

        Exception ex = null;
        InputSource inputSource = null;
        InputStream inputStream = null;
        try {
            File file = configFile();
            inputStream = new FileInputStream(file);
            inputSource = new InputSource("file://" + file.getAbsolutePath());
        } catch (Exception e) {
            ;
        }
        if (inputStream == null) {
            try {
                inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile());
                inputSource = new InputSource(getClass().getClassLoader().getResource(getConfigFile()).toString());
            } catch (Exception e) {
                ;
            }
        }

        if (inputStream == null) {
            System.out.println("Can't load server.xml");
            return;
        }

        try {
            inputSource.setByteStream(inputStream);
            digester.push(this);
            digester.parse(inputSource);
            inputStream.close();
        } catch (Exception e) {
            System.out.println("Catalina.start using " + getConfigFile() + ": " + e);
            e.printStackTrace(System.out);
            return;
        }

        // Replace System.out and System.err with a custom PrintStream
        // TODO: move to Embedded, make it configurable
        SystemLogHandler systemlog = new SystemLogHandler(System.out);
        System.setOut(systemlog);
        System.setErr(systemlog);

        // Start the new server
        if (_server instanceof Lifecycle) {
            try {
                _server.initialize();
            } catch (LifecycleException e) {
                log.error("Catalina.start", e);
            }
        }

        long t2 = System.currentTimeMillis();
        log.info("Initialization processed in " + (t2 - t1) + " ms");

    }

    /* 
     * Load using arguments
     */
    public void load(String args[]) {

        setCatalinaHome();
        setCatalinaBase();
        try {
            if (arguments(args))
                load();
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }
    }

    public void create() {

    }

    public void destroy() {

    }

    /**
     * Start a new server instance.
     */
    public void start(Tomcat50Bootstrap bootstrap) {
        _bootstrap = bootstrap;
        if (_server == null) {
            load();
        }

        long t1 = System.currentTimeMillis();

        // Start the new server
        if (_server instanceof Lifecycle) {
            try {
                ((Lifecycle) _server).start();
            } catch (LifecycleException e) {
                log.error("Catalina.start: ", e);
            }
        }

        long t2 = System.currentTimeMillis();
        log.info("Server startup in " + (t2 - t1) + " ms");

        //        try {
        //            // Register shutdown hook
        //            if (_useShutdownHook) {
        //                if (_shutdownHook == null) {
        //                    _shutdownHook = new CatalinaShutdownHook();
        //                }
        //                Runtime.getRuntime().addShutdownHook(_shutdownHook);
        //            }
        //        } catch (Throwable t) {
        //            // This will fail on JDK 1.2. Ignoring, as Tomcat can run
        //            // fine without the shutdown hook.
        //        }

        if (await) {
            if (_bootstrap != null) {
                if (_bootstrap.getBrowserExe() != null)
                    runBrowser(_bootstrap.getBrowserExe(), _bootstrap.getBrowserURL());
                _bootstrap.notifyComplete();
            }

            await();

            //Stop the browser process if there is one
            if (_browserProcess != null) {
                _browserProcess.destroy();
            }
            //It takes too long to stop the server the normal way so we will just terminate the process
            System.out.println("Apache Tomcat stopped");
            System.exit(0);
        }

    }

    /**
     * Stop an existing server instance.
     */
    public void stop() {

        //        try {
        //            // Remove the ShutdownHook first so that server.stop() 
        //            // doesn't get invoked twice
        //            if (_useShutdownHook) {
        //                Runtime.getRuntime().removeShutdownHook(_shutdownHook);
        //            }
        //        } catch (Throwable t) {
        //            // This will fail on JDK 1.2. Ignoring, as Tomcat can run
        //            // fine without the shutdown hook.
        //        }

        // Shut down the server
        //        if (server instanceof Lifecycle) {
        //            try {
        //                ((Lifecycle) server).stop();
        //            } catch (LifecycleException e) {
        //                log.error("Catalina.stop", e);
        //            }
        //        }
        //       
        //        System.exit(0);
    }

    /**
     * Await and shutdown.
     */
    public void await() {

        _server.await();

    }

    /**
     * Print usage information for this application.
     */
    protected void usage() {

        System.out.println("usage: java org.apache.catalina.startup.Catalina" + " [ -config {pathname} ] [ -debug ]"
                + " [ -nonaming ] { start | stop }");

    }

    public void finalize() {
        if (_browserProcess != null)
            _browserProcess.destroy();
    }

    private void runBrowser(String command, String parms) {
        Runtime r = Runtime.getRuntime();
        String env[] = new String[0];

        try {
            _browserProcess = r.exec('"' + command + '"' + (parms == null ? "" : (" " + parms)));
            //_browserProcess = r.exec(command+' ' + (parms == null ? "" : (" " + parms)));
            IDETool.slurpProcessOutput(_browserProcess);
        } catch (IOException e) {
            MessageLog.writeErrorMessage("runBrowser", e, this);
        }
    }

    /**
     * Sets the shutdown properties for this server
     */
    public void setShutdownProperties(Tomcat50ShutdownProperties props) {
        _shutdown = props;
    }
    // --------------------------------------- CatalinaShutdownHook Inner Class

    // XXX Should be moved to embedded !
    /**
     * Shutdown hook which will perform a clean shutdown of Catalina if needed.
     */
    protected class CatalinaShutdownHook extends Thread {

        public void run() {

            if (_server != null) {
                Tomcat50Engine.this.stop();
            }

        }

    }

    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
            .getLog(Tomcat50Engine.class);

}

// ------------------------------------------------------------ Private Classes

/**
 * Rule that sets the parent class loader for the top object on the stack,
 * which must be a <code>Container</code>.
 */

final class SetParentClassLoaderRule extends Rule {

    public SetParentClassLoaderRule(ClassLoader parentClassLoader) {

        this.parentClassLoader = parentClassLoader;

    }

    ClassLoader parentClassLoader = null;

    public void begin(String namespace, String name, Attributes attributes) throws Exception {

        if (digester.getLogger().isDebugEnabled())
            digester.getLogger().debug("Setting parent class loader");

        Container top = (Container) digester.peek();
        top.setParentClassLoader(parentClassLoader);

    }

}