xtremweb.communications.HTTPServer.java Source code

Java tutorial

Introduction

Here is the source code for xtremweb.communications.HTTPServer.java

Source

/*
 * Copyrights     : CNRS
 * Author         : Oleg Lodygensky
 * Acknowledgment : XtremWeb-HEP is based on XtremWeb 1.8.0 by inria : http://www.xtremweb.net/
 * Web            : http://www.xtremweb-hep.org
 *
 *      This file is part of XtremWeb-HEP.
 *
 *    XtremWeb-HEP is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    XtremWeb-HEP 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 General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with XtremWeb-HEP.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package xtremweb.communications;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.rmi.RemoteException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

import org.apache.commons.httpclient.HttpVersion;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;

import xtremweb.common.XWConfigurator;
import xtremweb.common.XWPropertyDefs;
import xtremweb.common.XWRole;

/**
 * <p>
 * This class implements a generic HTTP server<br />
 * This instanciates a new CommHandler on each new connection.
 * </p>
 * <p>
 * This is subject to replace WebServer so that all our servers extend
 * CommServer
 * </p>
 * <p>
 * This uses org.eclipse.jetty.Server where everything is done.<br />
 * </p>
 *
 * <p>
 * Created: March 30th, 2006
 * </p>
 *
 * @see CommServer
 * @author Oleg Lodygensky
 * @since RPCXW
 */

public class HTTPServer extends CommServer {

    /**
     * This is the Jetty HTTP server
     */
    private final Server httpServer;

    /**
     * This only calls super()
     */
    public HTTPServer() {
        super("HTTPServer");
        httpServer = new Server();
    }

    /**
     * This initializes communications
     *
     * @see CommServer#initComm(XWConfigurator, Handler)
     */
    @Override
    public void initComm(final XWConfigurator prop, final Handler handler) throws RemoteException {

        setPort(Connection.HTTPPORT.defaultPortValue());

        if (prop.getRole() == XWRole.WORKER) {
            setPort(Connection.HTTPWORKERPORT.defaultPortValue());
        }
        try {
            final int httpPort = (prop.getRole() == XWRole.WORKER
                    ? Integer.parseInt(prop.getProperty(Connection.HTTPPORT.toString()))
                    : Integer.parseInt(prop.getProperty(Connection.HTTPWORKERPORT.toString())));

            setPort(httpPort);

            final File keyFile = prop.getKeyStoreFile();

            if ((keyFile == null) || (!keyFile.exists()) || (prop.getRole() == XWRole.WORKER)) {

                getLogger().warn("unsecured communications : not using SSL");

                final HttpConfiguration httpConfig = new HttpConfiguration();
                httpConfig.setSecureScheme("https");
                httpConfig.setSecurePort(8443);
                httpConfig.setOutputBufferSize(32768);

                final ServerConnector http = new ServerConnector(httpServer, new HttpConnectionFactory(httpConfig));
                http.setPort(getPort());
                http.setIdleTimeout(30000);
                httpServer.setConnectors(new Connector[] { http });
            } else {
                initSecuredLayer(prop);
            }

            setHandler(handler);
            final HandlerCollection handlers = new HandlerCollection();
            httpServer.setHandler(handlers);
            this.addHandler("/", getHandler());
            Runtime.getRuntime().addShutdownHook(new Thread(getName() + "Cleaner") {
                @Override
                public void run() {
                    cleanup();
                }
            });

            getLogger().info("started, listening on port : " + getPort());
        } catch (final Exception e) {
            getLogger().exception(e);
            getLogger().fatal(getName() + ": could not listen on port " + getPort() + " : " + e);
        }
    }

    /**
     * This initializes the secured layer
     * 
     * @param prop
     * @throws IOException
     * @throws CertificateException
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     */
    private void initSecuredLayer(final XWConfigurator prop)
            throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException {
        final String password = prop.getProperty(XWPropertyDefs.SSLKEYPASSWORD);
        final String passphrase = prop.getProperty(XWPropertyDefs.SSLKEYPASSPHRASE);
        final File fstore = File.createTempFile("xwcacert", null);
        try (final FileOutputStream sstore = new FileOutputStream(fstore)) {
            final int httpsPort = Integer.parseInt(prop.getProperty(Connection.HTTPSPORT.toString()));
            setPort(httpsPort);

            fstore.deleteOnExit();
            final KeyStore store = prop.getKeyStore();
            store.store(sstore, password.toCharArray());
            getLogger().debug("HTTPS keystore = " + fstore.getAbsolutePath());
            final SslContextFactory sslContextFactory = new SslContextFactory(fstore.getAbsolutePath());
            sslContextFactory.setKeyStorePassword(password);
            sslContextFactory.setKeyManagerPassword(passphrase);
            sslContextFactory.setTrustStore(store);
            sslContextFactory.setTrustStorePassword(password);
            sslContextFactory.setWantClientAuth(true);

            final HttpConfiguration http_config = new HttpConfiguration();
            http_config.setSecureScheme("https");
            http_config.setSecurePort(getPort());
            http_config.setOutputBufferSize(32768);

            final HttpConfiguration https_config = new HttpConfiguration(http_config);
            final SecureRequestCustomizer src = new SecureRequestCustomizer();
            src.setStsMaxAge(2000);
            src.setStsIncludeSubDomains(true);
            https_config.addCustomizer(src);

            final ServerConnector https = new ServerConnector(httpServer,
                    new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.toString()),
                    new HttpConnectionFactory(https_config));
            https.setPort(getPort());
            https.setIdleTimeout(500000);

            httpServer.setConnectors(new Connector[] { https });

        }
    }

    /**
     * This adds an handler
     *
     * @param h
     *            is the handler to add
     */
    public void addHandler(final Handler h) {
        try {
            getLogger().debug("addHandler " + h.getClass());
            final HandlerCollection handlers = (HandlerCollection) httpServer.getHandler();
            handlers.addHandler(h);
        } catch (final Exception e) {
            getLogger().exception("Can't add handler", e);
        }
    }

    /**
     * This adds an resource handler which will answer from HTML files
     *
     * @param contextPath
     *            is the path of the url accessed
     * @param h
     *            is the handler to add
     */
    public void addHandler(final String contextPath, final Handler h) {
        final ContextHandler context = new ContextHandler();
        context.setContextPath(contextPath);
        context.setHandler(h);
        addHandler(context);
    }

    /**
     * This adds an resource handler which will answer from HTML files
     *
     * @param contextPath
     *            is the path of the url accessed
     * @param lpath
     *            is the local path where to find HTML files
     */
    public void addHandler(final String contextPath, final String lpath) {
        final ContextHandler context = new ContextHandler();
        context.setContextPath(contextPath);
        context.setResourceBase(lpath);
        context.setHandler(new ResourceHandler());
        addHandler(context);
    }

    /**
     * This adds an resource handler which will answer from HTML files
     *
     * @param contextPath
     *            is the path of the url accessed
     * @param path
     *            is the local path where to find HTML files
     */
    public void addHandler(final String contextPath, final File path) {
        final ContextHandler context = new ContextHandler();
        context.setContextPath(contextPath);
        context.setResourceBase(path.getAbsolutePath());
        context.setHandler(new ResourceHandler());
        addHandler(context);
    }

    /**
     * This calls httpServer#start()
     */
    @Override
    public void run() {

        try {
            httpServer.start();
            getLogger().info("started, listening on port : " + getPort());
            httpServer.join();
        } catch (final Exception e) {
            getLogger().exception("can't start HTTP server : " + getPort(), e);
        }
    }

    /**
     * This is called on program termination (CTRL+C) This deletes session from
     * server
     */
    protected void cleanup() {
        try {
            getLogger().debug("cleanup");
            httpServer.getHandler().stop();
        } catch (final Exception e) {
            getLogger().error("can't clean up");
        }
    }

}