fr.gael.dhus.server.http.TomcatServer.java Source code

Java tutorial

Introduction

Here is the source code for fr.gael.dhus.server.http.TomcatServer.java

Source

/*
 * Data Hub Service (DHuS) - For Space data distribution.
 * Copyright (C) 2013,2014,2015 GAEL Systems
 *
 * This file is part of DHuS software sources.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package fr.gael.dhus.server.http;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.logging.LogManager;

import javax.servlet.Servlet;
import javax.servlet.ServletException;

import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.startup.Catalina;
import org.apache.catalina.startup.Constants;
import org.apache.catalina.startup.ContextConfig;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.Tomcat.DefaultWebXmlListener;
import org.apache.catalina.valves.RemoteAddrValve;
import org.apache.catalina.valves.RemoteIpValve;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.juli.ClassLoaderLogManager;
import org.apache.tomcat.util.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.io.Files;

import fr.gael.dhus.server.http.web.WebApplication;
import fr.gael.dhus.server.http.web.WebServlet;
import fr.gael.dhus.system.config.ConfigurationManager;

@Component
public class TomcatServer {
    private static Log logger = LogFactory.getLog(TomcatServer.class);

    @Autowired
    private ConfigurationManager configurationManager;

    private String tomcatpath;

    private Catalina cat;

    private ArrayList<StandardContext> contexts = new ArrayList<StandardContext>();

    /**
     * Initialize Tomcat inner datasets.
     */
    public void init() throws TomcatException {
        tomcatpath = configurationManager.getTomcatConfiguration().getPath();
        final String extractDirectory = tomcatpath;

        File extractDirectoryFile = new File(extractDirectory);
        logger.info("Starting tomcat in " + extractDirectoryFile.getPath());

        try {
            extract(extractDirectoryFile, extractDirectory);
            // create tomcat various paths
            new File(extractDirectory, "conf").mkdirs();
            File cfg = new File(ClassLoader.getSystemResource("server.xml").toURI());
            Files.copy(cfg, new File(extractDirectory, "conf/server.xml"));
            new File(extractDirectory, "logs").mkdirs();
            new File(extractDirectory, "webapps").mkdirs();
            new File(extractDirectory, "work").mkdirs();
            File tmpDir = new File(extractDirectory, "temp");
            tmpDir.mkdirs();

            System.setProperty("java.io.tmpdir", tmpDir.getAbsolutePath());
            System.setProperty("catalina.base", extractDirectoryFile.getAbsolutePath());
            System.setProperty("catalina.home", extractDirectoryFile.getAbsolutePath());

            cat = new Catalina();
        } catch (Exception e) {
            throw new TomcatException("Cannot initalize Tomcat environment.", e);
        }

        Runtime.getRuntime().addShutdownHook(new TomcatShutdownHook());
    }

    /**
     * This method Starts the Tomcat server.
     */
    public void start() throws TomcatException {
        if (cat == null)
            init();
        cat.start();
    }

    /**
     * This method Stops the Tomcat server.
     */
    public void stop() throws TomcatException {
        // Stop the embedded server
        cat.stop();
        cat = null;
    }

    public boolean isRunning() {
        return cat != null;
    }

    protected class TomcatShutdownHook extends Thread {
        protected TomcatShutdownHook() {
        }

        @Override
        public void run() {
            try {
                TomcatServer.this.stop();
            } catch (Throwable ex) {
                ExceptionUtils.handleThrowable(ex);
                logger.error("Fail to properly shutdown Tomcat:" + ex.getMessage());
            } finally {
                LogManager logManager = LogManager.getLogManager();
                if (logManager instanceof ClassLoaderLogManager) {
                    ((ClassLoaderLogManager) logManager).shutdown();
                }
            }
        }
    }

    protected void extract(File extract_directory_file, String extract_directory) throws Exception {
        if (extract_directory_file.exists()) {
            logger.debug("Clean extractDirectory");
            FileUtils.deleteDirectory(extract_directory_file);
        }

        if (!extract_directory_file.exists()) {
            boolean created = extract_directory_file.mkdirs();
            if (!created) {
                throw new Exception("FATAL: impossible to create directory:" + extract_directory_file.getPath());
            }
        }

        // ensure webapp dir is here
        boolean created = new File(extract_directory, "webapps").mkdirs();
        if (!created) {
            throw new Exception(
                    "FATAL: impossible to create directory:" + extract_directory_file.getPath() + "/webapps");

        }
        expandConfigurationFile("web.xml", extract_directory_file);
    }

    private static void expandConfigurationFile(String file_name, File extract_directory) throws Exception {
        InputStream inputStream = null;
        try {
            inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("conf/" + file_name);
            if (inputStream != null) {
                File confDirectory = new File(extract_directory, "conf");
                if (!confDirectory.exists()) {
                    confDirectory.mkdirs();
                }
                expand(inputStream, new File(confDirectory, file_name));
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }

    }

    private static void expand(InputStream input, File file) throws IOException {
        BufferedOutputStream output = null;
        try {
            output = new BufferedOutputStream(new FileOutputStream(file));
            byte buffer[] = new byte[2048];
            while (true) {
                int n = input.read(buffer);
                if (n <= 0) {
                    break;
                }
                output.write(buffer, 0, n);
            }
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    // Ignore
                }
            }
        }
    }

    public void install(WebApplication web_application) throws TomcatException {
        try {
            String folder = web_application.getName() == "" ? "ROOT" : web_application.getName();
            if (web_application.hasWarStream()) {
                InputStream stream = web_application.getWarStream();
                if (stream == null) {
                    throw new TomcatException("Cannot install WebApplication " + web_application.getName()
                            + ". The referenced war " + "file does not exist.");
                }
                JarInputStream jis = new JarInputStream(stream);
                File destDir = new File(tomcatpath, "webapps/" + folder);

                byte[] buffer = new byte[4096];
                JarEntry file;
                while ((file = jis.getNextJarEntry()) != null) {
                    File f = new File(destDir + java.io.File.separator + file.getName());
                    if (file.isDirectory()) { // if its a directory, create it
                        f.mkdirs();
                        continue;
                    }
                    if (!f.getParentFile().exists()) {
                        f.getParentFile().mkdirs();
                    }

                    java.io.FileOutputStream fos = new java.io.FileOutputStream(f);
                    int read;
                    while ((read = jis.read(buffer)) != -1) {
                        fos.write(buffer, 0, read);
                    }
                    fos.flush();
                    fos.close();
                }
                jis.close();
            }
            web_application.configure(new File(tomcatpath, "webapps/" + folder).getPath());

            StandardEngine engine = (StandardEngine) cat.getServer().findServices()[0].getContainer();
            Container container = engine.findChild(engine.getDefaultHost());

            StandardContext ctx = new StandardContext();
            String url = (web_application.getName() == "" ? "" : "/") + web_application.getName();
            ctx.setName(url);
            ctx.setPath(url);
            ctx.setDocBase(new File(tomcatpath, "webapps/" + folder).getPath());

            ctx.addLifecycleListener(new DefaultWebXmlListener());
            ctx.setConfigFile(getWebappConfigFile(new File(tomcatpath, "webapps/" + folder).getPath(), url));

            ContextConfig ctxCfg = new ContextConfig();
            ctx.addLifecycleListener(ctxCfg);

            ctxCfg.setDefaultWebXml("fr/gael/dhus/server/http/global-web.xml");

            container.addChild(ctx);

            contexts.add(ctx);

            List<WebServlet> servlets = web_application.getServlets();

            for (WebServlet servlet : servlets) {
                addServlet(ctx, servlet.getServletName(), servlet.getUrlPattern(), servlet.getServlet(),
                        servlet.isLoadOnStartup());
            }

            List<String> welcomeFiles = web_application.getWelcomeFiles();

            for (String welcomeFile : welcomeFiles) {
                ctx.addWelcomeFile(welcomeFile);
            }

            if (web_application.getAllow() != null || web_application.getDeny() != null) {
                RemoteIpValve valve = new RemoteIpValve();
                valve.setRemoteIpHeader("x-forwarded-for");
                valve.setProxiesHeader("x-forwarded-by");
                valve.setProtocolHeader("x-forwarded-proto");
                ctx.addValve(valve);

                RemoteAddrValve valve_addr = new RemoteAddrValve();
                valve_addr.setAllow(web_application.getAllow());
                valve_addr.setDeny(web_application.getDeny());
                ctx.addValve(valve_addr);
            }
        } catch (Exception e) {
            throw new TomcatException("Cannot install service", e);
        }
    }

    public void install(fr.gael.dhus.server.http.WebApplication web_application) throws TomcatException {
        logger.info("Installing webapp " + web_application);
        String appName = web_application.getName();
        String folder;

        if (appName.trim().isEmpty()) {
            folder = "ROOT";
        } else {
            folder = appName;
        }

        try {
            if (web_application.hasWarStream()) {
                InputStream stream = web_application.getWarStream();
                if (stream == null) {
                    throw new TomcatException("Cannot install webApplication " + web_application.getName()
                            + ". The referenced war file does not exist.");
                }
                JarInputStream jis = new JarInputStream(stream);
                File destDir = new File(tomcatpath, "webapps/" + folder);

                byte[] buffer = new byte[4096];
                JarEntry file;
                while ((file = jis.getNextJarEntry()) != null) {
                    File f = new File(destDir + java.io.File.separator + file.getName());
                    if (file.isDirectory()) { // if its a directory, create it
                        f.mkdirs();
                        continue;
                    }
                    if (!f.getParentFile().exists()) {
                        f.getParentFile().mkdirs();
                    }

                    java.io.FileOutputStream fos = new java.io.FileOutputStream(f);
                    int read;
                    while ((read = jis.read(buffer)) != -1) {
                        fos.write(buffer, 0, read);
                    }
                    fos.flush();
                    fos.close();
                }
                jis.close();
            }
            web_application.configure(new File(tomcatpath, "webapps/" + folder).getPath());

            StandardEngine engine = (StandardEngine) cat.getServer().findServices()[0].getContainer();
            Container container = engine.findChild(engine.getDefaultHost());

            StandardContext ctx = new StandardContext();
            String url = (web_application.getName() == "" ? "" : "/") + web_application.getName();
            ctx.setName(url);
            ctx.setPath(url);
            ctx.setDocBase(new File(tomcatpath, "webapps/" + folder).getPath());

            ctx.addLifecycleListener(new DefaultWebXmlListener());
            ctx.setConfigFile(getWebappConfigFile(new File(tomcatpath, "webapps/" + folder).getPath(), url));

            ContextConfig ctxCfg = new ContextConfig();
            ctx.addLifecycleListener(ctxCfg);

            ctxCfg.setDefaultWebXml("fr/gael/dhus/server/http/global-web.xml");

            container.addChild(ctx);

            List<String> welcomeFiles = web_application.getWelcomeFiles();

            for (String welcomeFile : welcomeFiles) {
                ctx.addWelcomeFile(welcomeFile);
            }

            if (web_application.getAllow() != null || web_application.getDeny() != null) {
                RemoteIpValve valve = new RemoteIpValve();
                valve.setRemoteIpHeader("x-forwarded-for");
                valve.setProxiesHeader("x-forwarded-by");
                valve.setProtocolHeader("x-forwarded-proto");
                ctx.addValve(valve);

                RemoteAddrValve valve_addr = new RemoteAddrValve();
                valve_addr.setAllow(web_application.getAllow());
                valve_addr.setDeny(web_application.getDeny());
                ctx.addValve(valve_addr);
            }

            web_application.checkInstallation();
        } catch (Exception e) {
            throw new TomcatException("Cannot install webApplication " + web_application.getName(), e);
        }
    }

    public void install(WebServlet web_servlet) {
        Context ctx = findContext(web_servlet.getUrlBase());
        addServlet(ctx, web_servlet.getServletName(), web_servlet.getUrlPattern(), web_servlet.getServlet(),
                web_servlet.isLoadOnStartup());
    }

    private Wrapper addServlet(Context ctx, String servlet_name, String url_mapping, Servlet servlet,
            boolean load_on_startup) {
        Wrapper wrapper = Tomcat.addServlet(ctx, servlet_name, servlet);
        ctx.addServletMapping(url_mapping, servlet_name);
        if (load_on_startup) {
            try {
                wrapper.load();
            } catch (ServletException e) {
                e.printStackTrace();
            }
        }
        return wrapper;
    }

    public void await() {
        cat.getServer().await();
    }

    private Context findContext(String context_name) {
        StandardEngine engine = (StandardEngine) cat.getServer().findServices()[0].getContainer();
        Container container = engine.findChild(engine.getDefaultHost());
        StandardContext context = (StandardContext) (container.findChild(context_name));

        if (context != null) {
            return context;
        }
        context = new StandardContext();
        context.setName(context_name);
        context.setPath(context_name);
        context.setDocBase("");

        context.addLifecycleListener(new DefaultWebXmlListener());

        ContextConfig ctxCfg = new ContextConfig();
        context.addLifecycleListener(ctxCfg);

        // prevent it from looking ( if it finds one - it'll have dup error )
        ctxCfg.setDefaultWebXml(Constants.NoDefaultWebXml);

        container.addChild(context);
        contexts.add(context);
        return context;
    }

    public int getPort() {
        Connector connector = cat.getServer().findServices()[0].findConnectors()[0];
        return connector.getPort();
    }

    public String getPath() {
        return this.tomcatpath;
    }

    protected URL getWebappConfigFile(String path, String url) {
        File docBase = new File(path);
        if (docBase.isDirectory()) {
            return getWebappConfigFileFromDirectory(docBase, url);
        } else {
            return getWebappConfigFileFromJar(docBase, url);
        }
    }

    private URL getWebappConfigFileFromDirectory(File docBase, String url) {
        URL result = null;
        File webAppContextXml = new File(docBase, Constants.ApplicationContextXml);
        if (webAppContextXml.exists()) {
            try {
                result = webAppContextXml.toURI().toURL();
            } catch (MalformedURLException e) {
                logger.warn("Unable to determine web application context.xml " + docBase, e);
            }
        }
        return result;
    }

    private URL getWebappConfigFileFromJar(File docBase, String url) {
        URL result = null;
        JarFile jar = null;
        try {
            jar = new JarFile(docBase);
            JarEntry entry = jar.getJarEntry(Constants.ApplicationContextXml);
            if (entry != null) {
                result = new URL("jar:" + docBase.toURI().toString() + "!/" + Constants.ApplicationContextXml);
            }
        } catch (IOException e) {
            logger.warn("Unable to determine web application context.xml " + docBase, e);
        } finally {
            if (jar != null) {
                try {
                    jar.close();
                } catch (IOException e) {
                    // ignore
                }
            }
        }
        return result;
    }
}