Java tutorial
/** * 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(); } } }