All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.devops4j.embedded.EmbeddedHttpServer Maven / Gradle / Ivy

There is a newer version: 0.0.4-alpha
Show newest version
package com.devops4j.embedded;

import com.devops4j.embedded.handler.DelegateHttpHandler;
import com.devops4j.embedded.handler.StaticHttpHandler;
import com.devops4j.embedded.servlet.EmbeddedServletConfig;
import com.devops4j.embedded.httpserver.HttpServer;
import com.devops4j.embedded.httpserver.HttpsConfigurator;
import com.devops4j.embedded.httpserver.HttpsServer;
import com.devops4j.logtrace4j.ErrorContextFactory;
import com.devops4j.message.MessageFormatter;
import com.devops4j.reflection4j.GlobalSystemMetadata;
import com.devops4j.reflection4j.MetaClass;
import com.devops4j.reflection4j.resource.ClassScanner;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

public class EmbeddedHttpServer {
    /**
     * 服务器
     */
    HttpServer httpServer;
    HttpsServer httpsServer;
    /**
     * 线程池
     */
    ExecutorService threadPool;
    /**
     * 定时器
     */
    Timer timer;
    final Properties configs = new Properties();
    private Logger logger;

    final Map servlets = new HashMap();

    final Map> urlPatterns = new HashMap();

    static EmbeddedHttpServer INSTANCE = new EmbeddedHttpServer();

    public EmbeddedHttpServer() {
        this.logger = Logger.getLogger(this.getClass().getName());
    }

    EmbeddedHttpServer registerServlet(String name, Set urlPatterns, final HttpServlet servlet) {
        if (servlet == null) {
            throw new NullPointerException("servlet '" + name + "' is null");
        }
        if (this.servlets.containsKey(name)) {
            throw ErrorContextFactory.instance().message("exists servlet name '{}'", name).runtimeException();
        }

        this.urlPatterns.put(name, urlPatterns);
        for (String urlPattern : urlPatterns) {
            this.servlets.put(urlPattern, servlet);
        }
        return this;
    }

    /**
     * 注册Servlet
     *
     * @param name        Servlet名字
     * @param urlPatterns Servlet
     * @param servlet     Servlet
     * @return 服务器
     */
    EmbeddedHttpServer registerServlet(String name, String[] urlPatterns, final HttpServlet servlet) {
        Set urlPatterns_0 = new LinkedHashSet();
        for (String urlPattern : urlPatterns) {
            urlPatterns_0.add(urlPattern);
        }
        return registerServlet(name, urlPatterns_0, servlet);
    }

    public static EmbeddedHttpServer getInstance() {
        return INSTANCE;
    }

    void _destroy() {
        httpServer = null;
        httpsServer = null;
        threadPool = null;
    }

    public static void destroy() {
        if (INSTANCE != null) {
            INSTANCE._destroy();
            INSTANCE = null;
        }
    }

    public void start() throws IOException {
        start(Thread.currentThread().getContextClassLoader());
    }

    void initConfig() {
        configs.clear();
        Properties systemProp = System.getProperties();
        String serverFile = systemProp.getProperty("server.properties");
        InputStream is = null;
        try {
            if(serverFile != null){
                File file = new File(serverFile);
                is = new FileInputStream(file);
            }else{
                URL url = this.getClass().getClassLoader().getResource("server.properties");
                if (url == null) {
                    error("not found httpServer.properties");
                    return;
                }
                is = url.openStream();
            }
            configs.load(is);
        } catch (IOException e) {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e1) {
                    //nothing
                }
            }
        }
        for (Object key : configs.keySet()) {
            error("config key {}:'{}'", key, configs.get(key));
        }
    }

    void initServlet() {
        //扫描包含Servlet的包路径,多个用英文分号分割
        String scanPackages_ = configs.getProperty("server.servlet.packages", "com.devops4j.embedded");
        info("scan package'{}'", scanPackages_);
        String[] scanPackages = scanPackages_.split(";");
        //是否扫描子包
        String scanSubPackage_ = configs.getProperty("server.servlet.scan.subpackage", "true");
        info("scan subpackage '{}'", scanSubPackage_);
        ClassScanner classScanner = new ClassScanner(this.getClass().getClassLoader(), Boolean.valueOf(scanSubPackage_));
        for (String scanPackage : scanPackages) {
            classScanner.scan(scanPackage, new ClassScanner.AnnotatedWithFilter(WebServlet.class));
        }
        for (Class servletClass : classScanner.getClasses()) {
            WebServlet webServletAnn = (WebServlet) servletClass.getAnnotation(WebServlet.class);
            MetaClass metaClass = GlobalSystemMetadata.forClass(servletClass);
            HttpServlet servlet = metaClass.newInstance();
            EmbeddedServletConfig config = new EmbeddedServletConfig();
            //首次启动初始化Servlet
            try {
                servlet.init(config);
            } catch (ServletException e) {
                throw new RuntimeException("初始化Servlet发生失败", e);
            }
            Set urlPatterns_0 = new LinkedHashSet();
            for (String urlPattern : webServletAnn.value()) {
                urlPatterns_0.add(urlPattern);
            }
            for (String urlPattern : webServletAnn.urlPatterns()) {
                urlPatterns_0.add(urlPattern);
            }
            registerServlet(webServletAnn.name(), urlPatterns_0, servlet);
        }
    }

    public void start(ClassLoader classLoader) throws IOException {
        if (httpServer != null || httpsServer != null) {
            stop();
            _destroy();
        }
        initConfig();
        if (this.timer == null) {
            int autoShutdownSeconds = Integer.valueOf(configs.getProperty("server.shutdown.auto.seconds", "-1"));
            if (autoShutdownSeconds > 0) {
                info("auto shutdown timer '{}'", autoShutdownSeconds);
                this.timer = new Timer("auto shutdown timer", true);
                //自动关闭
                this.timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        info("auto shutdown");
                        EmbeddedHttpServer.getInstance().stop();
                        System.exit(0);
                    }
                }, autoShutdownSeconds * 1000);
            }
        }
        initServlet();
        this.threadPool = Executors.newCachedThreadPool();
        String enableHttp = configs.getProperty("server.http.enable", "true");
        String enableHttps = configs.getProperty("server.https.enable", "false");
        if(Boolean.valueOf(enableHttp)){
            startHttp();
        }
        if(Boolean.valueOf(enableHttps)) {
            startHttps();
        }
        //执行关机钩子,销毁Servlet
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Execute Hook.....");
                for (String name : servlets.keySet()) {
                    Servlet servlet = servlets.get(name);
                    servlet.destroy();
                }
            }
        }));
    }

    public void stop() {
        if (this.httpServer != null || this.httpsServer != null) {
            System.out.println("Server just now shutdown!");
            this.threadPool.shutdown();
            if (this.timer != null) {
                this.timer.cancel();
            }
            this.timer = null;
            if (this.httpServer != null) {
                //3秒后关闭
                this.httpServer.stop(3);
            }
            if (this.httpsServer != null) {
                //3秒后关闭
                this.httpsServer.stop(3);
            }
        } else {
            return;
        }

    }

    void startHttp() throws IOException {
        int port = Integer.valueOf(configs.getProperty("server.http.port","80"));
        this.httpServer = HttpServer.create(new InetSocketAddress(port), 0);
        this.httpServer.setExecutor(this.threadPool);
        boolean forceHttps = Boolean.valueOf(configs.getProperty("server.force.https","false"));
        String webapp = configs.getProperty("server.webapp.dir", "webapp");
        final DelegateHttpHandler delegateHttpHandler = new DelegateHttpHandler(this.getClass().getClassLoader(), threadPool, servlets, forceHttps);
        this.httpServer.createContext("/", new StaticHttpHandler(this.getClass().getClassLoader(), threadPool, forceHttps, webapp));
        for (String urlPattern : servlets.keySet()) {
            info("context '{}'", urlPattern);
            this.httpServer.createContext(urlPattern, delegateHttpHandler);
        }
        this.httpServer.start();
        System.out.println("Server is listening on port " + port);
    }

    void startHttps() throws IOException {
        int port = Integer.valueOf(configs.getProperty("server.https.port","443"));
        this.httpsServer = HttpsServer.create(new InetSocketAddress(port), 0);
        this.httpsServer.setExecutor(this.threadPool);
        SSLContext sslContext = null;
        ErrorContextFactory.instance().activity("启动HTTPS服务");
        try {
            sslContext = loadSslFile(configs.getProperty("server.https.ssl.cert.file", "ssl.cert"), configs.getProperty("server.https.ssl.cert.password",""));
        } catch (Exception e) {
            throw ErrorContextFactory.instance().message("加载证书发生错误").cause(e).runtimeException();
        }finally {
            ErrorContextFactory.instance().reset();
        }
        HttpsConfigurator conf = new HttpsConfigurator(sslContext);
        this.httpsServer.setHttpsConfigurator(conf);
        boolean forceHttps = Boolean.valueOf(configs.getProperty("server.force.https","false"));
        String webapp = configs.getProperty("server.webapp.dir", "webapp");
        final DelegateHttpHandler delegateHttpHandler = new DelegateHttpHandler(this.getClass().getClassLoader(), threadPool, servlets, forceHttps);
        this.httpsServer.createContext("/", new StaticHttpHandler(this.getClass().getClassLoader(), threadPool, forceHttps, webapp));
        for (String urlPattern : servlets.keySet()) {
            info("context '{}'", urlPattern);
            this.httpsServer.createContext(urlPattern, delegateHttpHandler);
        }
        this.httpsServer.start();
        System.out.println("Server is listening on port " + port);
    }

    /**
     * 记载SSL整数
     * @param httpsCertFile 证书文件classpath路径
     * @param password 密码
     * @return
     * @throws KeyStoreException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws CertificateException
     * @throws UnrecoverableKeyException
     * @throws KeyManagementException
     */
    SSLContext loadSslFile(String httpsCertFile, String password) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException, URISyntaxException {
        KeyStore ks = KeyStore.getInstance("JKS");
        URL certURL = getClass().getClassLoader().getResource(httpsCertFile);
        if (certURL == null) {
            throw ErrorContextFactory.instance().message("https SSL cert '{}' not found", httpsCertFile).runtimeException();
        }
        InputStream is = null;
        try {
            is = certURL.openStream();
            ks.load(is, password.toCharArray());
        } finally {
            if (is != null) {
                is.close();
            }
        }
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, password.toCharArray());
        SSLContext sslContext = SSLContext.getInstance("SSLv3");
        sslContext.init(kmf.getKeyManagers(), null, null);
        return sslContext;
    }

    public void error(String format, Object... args) {
        this.logger.log(Level.WARNING, MessageFormatter.format(format, args));
    }

    public void debug(String format, Object... args) {
        this.logger.log(Level.FINER, MessageFormatter.format(format, args));
    }

    public void info(String format, Object... args) {
        this.logger.log(Level.INFO, MessageFormatter.format(format, args));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy