com.trinity.engine.protocol.detail.TrinityConnectionManager.java Source code

Java tutorial

Introduction

Here is the source code for com.trinity.engine.protocol.detail.TrinityConnectionManager.java

Source

/**
 * This file is part of Trinity.
 *
 * Copyright (c) 2014 Agustin L. Alvarez <<wolftein1@gmail.com>>
 *
 * 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.
 */
package com.trinity.engine.protocol.detail;

import com.trinity.engine.protocol.Protocol;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.ChannelGroupFuture;
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 java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Define a pooling executor to handle multiple {@link TrinityConnection}
 */
public final class TrinityConnectionManager {
    private final ConcurrentMap<String, TrinityConnection> mRegistry;
    private final ChannelGroup mGroup;
    private final EventLoopGroup mBossGroup;
    private final EventLoopGroup mWorkerGroup;
    private final ServerBootstrap mBootstrap;
    private Protocol mProtocol;
    private AtomicReference<UncaughtExceptionHandler> mUncaughtExceptionHandler;

    /**
     * Default constructor for {@link TrinityConnectionManager}
     */
    public TrinityConnectionManager() {
        this.mRegistry = new ConcurrentHashMap<>();
        this.mGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        this.mBossGroup = new NioEventLoopGroup();
        this.mWorkerGroup = new NioEventLoopGroup();
        this.mBootstrap = new ServerBootstrap();
        this.mUncaughtExceptionHandler = new AtomicReference<>(new DefaultUncaughtExceptionHandler());
    }

    /**
     * Initialise the connection manager context
     *
     * @param configuration the configuration on which all connection executes
     */
    public void initialise(Protocol configuration) {
        mProtocol = configuration;
        mBootstrap.group(mBossGroup, mWorkerGroup).channel(NioServerSocketChannel.class)
                .childHandler(new ConnectionChannel(mProtocol.getLookupService(), this))
                .childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true);
    }

    /**
     * Retrieve the protocol of the connection manager context
     *
     * @return a reference to the connection manager context
     */
    public Protocol getProtocol() {
        return mProtocol;
    }

    /**
     * Binds the connection manager to an address
     *
     * @param address the internet address to bind to
     * @param port    the port on which the connection listen
     * @return true if the connection manager was able to bind to the address given
     */
    public boolean bind(String address, int port) {
        boolean isValid = false;
        try {
            mGroup.add(mBootstrap.bind(address, port).sync().channel());
            isValid = true;
        } catch (InterruptedException exception) {
            getUncaughtExceptionHandler().uncaughtException(exception);
        }
        return isValid;
    }

    /**
     * Stops the connection manager and disconnect all connections
     *
     * @param reason the reason for disconnection
     */
    public void stop(String reason) {
        // Disconnect all connections from the main
        // channel of the manager
        disconnect(reason);

        // Disconnect the main channel of the manager
        final ChannelGroupFuture future = mGroup.close();
        try {
            future.await();
        } catch (InterruptedException exception) {
            getUncaughtExceptionHandler().uncaughtException(exception);
        }
        mBossGroup.shutdownGracefully();
        mWorkerGroup.shutdownGracefully();
    }

    /**
     * Disconnect all connections attached to the context
     *
     * @param reason the reason why the disconnection
     */
    public void disconnect(String reason) {
        mRegistry.values().forEach((Connection) -> Connection.disconnect(reason));
    }

    /**
     * Pulse all connections currently connected to the context
     */
    public void pulse() {
        mRegistry.values().forEach(TrinityConnection::pulse);
    }

    /**
     * Adds a new connection to the pool
     *
     * @param connection the connection to add to the pool
     */
    public void add(TrinityConnection connection) {
        mGroup.add(connection.mChannel);
        mRegistry.put(connection.getUniqueId(), connection);
    }

    /**
     * Removes a connection from the pool
     *
     * @param connection the connection to remove from the pool
     */
    public void remove(TrinityConnection connection) {
        mRegistry.remove(connection.getUniqueId());
        mGroup.remove(connection.mChannel);
    }

    /**
     * Sets the uncaught exception handler to be used for this connection.
     *
     * @param handler the new handler of the connection
     */
    public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
        mUncaughtExceptionHandler.set(handler);
    }

    /**
     * Retrieve the uncaught exception handler of this connection
     *
     * @return a reference to the exception handler of the connection
     */
    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return mUncaughtExceptionHandler.get();
    }

    /**
     * Define an exception handler for any exception that occurs
     */
    public static interface UncaughtExceptionHandler {
        /**
         * Called when an exception occurs
         *
         * @param exception the exception triggered
         */
        public void uncaughtException(Exception exception);
    }

    /**
     * Define a default
     */
    public static final class DefaultUncaughtExceptionHandler implements UncaughtExceptionHandler {
        /**
         * {@inheritDoc}
         */
        @Override
        public void uncaughtException(Exception exception) {
            exception.printStackTrace();
        }
    }
}