com.github.jonbonazza.puni.core.Application.java Source code

Java tutorial

Introduction

Here is the source code for com.github.jonbonazza.puni.core.Application.java

Source

/*
 * Copyright 2014 Jon Bonazza
 *
 * Jon Bonazza licenses this file to you 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.github.jonbonazza.puni.core;

import com.github.jonbonazza.puni.core.config.AppConfiguration;
import com.github.jonbonazza.puni.core.config.SSLConfiguration;
import com.github.jonbonazza.puni.core.exceptions.NoConfigurationException;
import com.github.jonbonazza.puni.core.mux.DefaultMuxer;
import com.github.jonbonazza.puni.core.mux.Muxer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Abstract base class for puni applications. Developers should subclass this class to provide application specific
 * logic for {@link Application#configure}.
 *
 */
public abstract class Application<T extends AppConfiguration> {

    private Class<T> configType;
    private T config;
    private Muxer muxer = new DefaultMuxer();

    private boolean bootstrapped = false;

    /**
     * Creates a new Application instance using the configType class for configuration.
     * @param configType The class to unmarshal configuration to.
     */
    public Application(Class<T> configType) {
        this.configType = configType;
    }

    private void bootstrap() throws Exception {
        SslContext sslContext = null;
        SSLConfiguration sslConfig = config.getSsl();
        if (config.getSsl().isEnabled()) {
            sslContext = SslContext.newServerContext(new File(sslConfig.getCert()),
                    new File(sslConfig.getPrivateKey()));
        }

        EventLoopGroup eventGroup = new NioEventLoopGroup(config.getEventLoopThreadCount());

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(eventGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new HttpInitializer(sslContext, muxer));
            Channel ch = b.bind(config.getPort()).sync().channel();
            ch.closeFuture().sync();
            bootstrapped = true;
        } finally {
            eventGroup.shutdownGracefully();
        }
    }

    /**
     * Loads YAML configuration from file, unmarshalling it into the provided class type.
     * @param file The file to load the configuration from. This must be called before
     * {@link Application#start} is called.
     * @throws IOException if something went wrong during loading.
     */
    public void loadConfiguration(File file) throws IOException {
        try (InputStream is = new FileInputStream(file)) {
            Yaml yaml = new Yaml();
            config = yaml.loadAs(is, configType);
        }
    }

    /**
     * Starts the application server. {@link Application#loadConfiguration} must already have been called
     * or a {@link com.github.jonbonazza.puni.core.exceptions.NoConfigurationException} will be thrown.
     * @throws Exception if something goes wrong during the startup process. If an exception is thrown, the server was
     * not started.
     */
    public void start() throws Exception {
        if (config == null) {
            throw new NoConfigurationException();
        }

        configure(config, muxer);
        bootstrap();
    }

    /**
     * Should be overridden by subclasses to further configure the application. For example, regeristing handlers with
     * the muxer or changing the muxer all together is done here.
     * @param configuration The configuration that was loaded from file.
     * @param muxer The default muxer is passed in for convenience. Is a different muxer is to be used,
     *              this parameter can be ignored.
     * @throws Exception Implementation should throw an exception is something goes wrong.
     */
    protected abstract void configure(T configuration, Muxer muxer) throws Exception;

    /**
     * Sets the muxer to use with the application. This can only be done before the application has been bootstrapped.
     * @param muxer The new muxer that should be used by the application
     * @throws Exception if called after the application has been bootstrapped.
     */
    public void setMuxer(Muxer muxer) throws Exception {
        if (bootstrapped)
            throw new Exception("Cannot change muxer once the application has been bootstrapped");

        this.muxer = muxer;
    }
}