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

org.wisdom.engine.server.WisdomServer Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * Wisdom-Framework
 * %%
 * Copyright (C) 2013 - 2014 Wisdom Framework
 * %%
 * 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.
 * #L%
 */
package org.wisdom.engine.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wisdom.api.configuration.ApplicationConfiguration;

import java.net.InetAddress;
import java.security.KeyStoreException;
import java.util.Random;

/**
 * The Wisdom Server.
 */
public class WisdomServer {

    private static final String KEY_HTTP_ADDRESS = "http.address";

    private static final Logger LOGGER = LoggerFactory.getLogger("wisdom-netty-engine");
    private final ServiceAccessor accessor;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private ChannelGroup group;
    private int httpPort;
    private int httpsPort;
    private InetAddress address;

    /**
     * Creates a new instance of the Wisdom Server.
     * @param accessor the structure letting access services.
     */
    public WisdomServer(ServiceAccessor accessor) {
        this.accessor = accessor;
    }

    /**
     * Starts the server.
     * @throws InterruptedException if the server is interrupted.
     */
    public void start() throws InterruptedException {
        LOGGER.info("Starting Wisdom server");
        httpPort = accessor.getConfiguration().getIntegerWithDefault(ApplicationConfiguration.HTTP_PORT, 9000);
        httpsPort = accessor.getConfiguration().getIntegerWithDefault(ApplicationConfiguration.HTTPS_PORT, -1);

        initializeInetAddress();

        group = new DefaultChannelGroup("wisdom-channels", GlobalEventExecutor.INSTANCE);
        // Configure the server.
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();

        try {
            // Here we need to start the different channels.
            // Negative ports disable the channels. Usually, we use -1.
            // 0 indicates a random port.
            initializeHTTP();
            initializeHTTPS();
        } catch (Exception e) {
            LOGGER.error("Cannot initialize Wisdom", e);
            group.close().sync();
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
            onError();
        }
    }

    private void initializeHTTPS() throws Exception {
        //HTTPS
        if (httpsPort == 0) {
            Random random = new Random();
            for (int i = 0; httpsPort == 0 && i < 30; i++) {
                int port = 9000 + random.nextInt(10000);
                try {
                    LOGGER.debug("Random port lookup - Trying with {}", port);
                    bind(port, true);
                    httpsPort = port;
                    LOGGER.info("Wisdom is going to serve HTTPS requests on port " + httpsPort);
                } catch (Exception e) {
                    LOGGER.debug("Cannot bind on port {} (port already used probably)", port, e);
                }
            }

            // If the port is still 0, we were not able to bind on any port.
            if (httpsPort == 0) {
                throw new IllegalStateException("Cannot find a free port for HTTPS after 30 tries");
            }
        } else if (httpsPort >= 0) {
            bind(httpsPort, true);
            LOGGER.info("Wisdom is going to serve HTTPS requests on port " + httpsPort);
        }
    }

    private void initializeHTTP() throws Exception {
        // HTTP
        if (httpPort == 0) {
            Random random = new Random();
            for (int i = 0; httpPort == 0  && i < 30; i++) {
                int port = 9000 + random.nextInt(10000);
                try {
                    LOGGER.debug("Random port lookup - Trying with {}", port);
                    bind(port, false);
                    httpPort = port;
                    LOGGER.info("Wisdom is going to serve HTTP requests on port " + httpPort);
                } catch (Exception e) {
                    LOGGER.debug("Cannot bind on port {} (port already used probably)", port, e);
                }
            }

            // If the port is still 0, we were not able to bind on any port.
            if (httpPort == 0) {
                throw new IllegalStateException("Cannot find a free port for HTTP after 30 tries");
            }
        } else if (httpPort >= 0) {
            bind(httpPort, false);
            LOGGER.info("Wisdom is going to serve HTTP requests on port " + httpPort);
        }
    }

    private void initializeInetAddress() {
        address = null;
        try {
            if (accessor.getConfiguration().get(KEY_HTTP_ADDRESS) != null) {
                address = InetAddress.getByName(accessor.getConfiguration().get(KEY_HTTP_ADDRESS));
            }
            if (System.getProperties().containsKey(KEY_HTTP_ADDRESS)) {
                address = InetAddress.getByName(System.getProperty(KEY_HTTP_ADDRESS));
            }
        } catch (Exception e) {
            LOGGER.error("Could not understand http.address", e);
            onError();
        }
    }

    private void bind(int port, boolean secure) throws KeyStoreException, InterruptedException {
        ServerBootstrap http = new ServerBootstrap();
        http.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new WisdomServerInitializer(accessor, secure));
        group.add(http.bind(address, port).sync().channel());
    }

    private void onError() {
        System.exit(-1); //NOSONAR
    }

    /**
     * Stops the server.
     */
    public void stop() {
        try {
            group.close().sync();
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
            LOGGER.info("Wisdom server has been stopped gracefully");
        } catch (InterruptedException e) {
            LOGGER.warn("Cannot stop the Wisdom server gracefully", e);
        }
    }

    /**
     * @return the hostname.
     */
    public String hostname() {
        if (address == null) {
            return "localhost";
        } else {
            return address.getHostName();
        }
    }

    /**
     * @return the HTTP port on which the current HTTP server is bound. {@literal -1} means that the HTTP connection
     * is not enabled.
     */
    public int httpPort() {
        return httpPort;
    }

    /**
     * @return the HTTP port on which the current HTTPS server is bound. {@literal -1} means that the HTTPS connection
     * is not enabled.
     */
    public int httpsPort() {
        return httpsPort;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy