Java tutorial
// Northerner Cyril, an online, token-based implementation of the game // Carcassonne // This is part of the "server" module // Copyright (C) 2012 Ben Wiederhake // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. package cyril.server.io; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import cyril.common.ProtocolConstants; import cyril.server.auth.Authentication; import cyril.server.auth.Login; import cyril.server.io.SpamInitializer.ConnectionState; import cyril.server.io.SpamInitializer.SpamListener; public class LessThanNullSuite { public static final class AbortOnConnectService implements NorthernerService { @Override public boolean mayOpenConection(Login l) { return true; } @Override public void handleNewSession(Channel ch, Login l) { ch.close(); } } public static final class PermitEverythingAuthentication implements Authentication<Void> { @Override public Void wrap(Channel ch) { return null; } @Override public boolean isValidUsernameLength(Void ch, int usernameLength) { return usernameLength < 10; } @Override public Login getLogin(Void ch, String user) { return new Login(user, new byte[0]); } @Override public Login createLogin(Void ch) { String name = Long.toHexString(ProtocolConstants.RANDOM.nextLong()); return new Login(name, new byte[0]); } } public static final class SpamToConsoleListener implements SpamListener { @Override public void stateChanged(Channel ch, ConnectionState connState) { System.out.println("Channel " + ch + " => " + connState); } } public static final <C> NorthernerServer startNortherner(EventLoopGroup parentGroup, EventLoopGroup childGroup, int port, NorthernerService service, Authentication<C> auth, SpamListener listener) { ServerBootstrap b = new ServerBootstrap(); try { AuthInitializer<C> ai = new AuthInitializer<C>(service, auth, listener); SpamInitializer si = new SpamInitializer(ai, listener); b.group(parentGroup, childGroup).channel(NioServerSocketChannel.class).localAddress(port) .childHandler(si); // Bind and start to accept incoming connections. ChannelFuture f = b.bind(); System.out.println("Service " + service + " has gone live on port " + port); return new NorthernerServer(b, f); } finally { b.shutdown(); } } public static final <C> NorthernerServer startNortherner(NorthernerService service, Authentication<C> auth, SpamListener listener) { return startNortherner(new NioEventLoopGroup(), new NioEventLoopGroup(), ProtocolConstants.DEFAULT_PORT, service, auth, listener); } public static final void runStandalone(NorthernerServer ns) { try { ServerSocketChannel ch = (ServerSocketChannel) ns.channelFuture.sync().channel(); System.out.println("Using channel " + ch + " (" + ch.getClass().getSimpleName() + ")"); ch.closeFuture().sync(); System.out.println("Has closed?!"); } catch (InterruptedException e) { throw new ChannelException(e); } finally { System.out.println("Shutting down..."); ns.bootstrap.shutdown(); } } public static void main(String[] args) { runStandalone(startNortherner(new AbortOnConnectService(), new PermitEverythingAuthentication(), new SpamToConsoleListener())); /** * Correct shutdown procedure * * <pre> * ChannelFuture cf = serverChannel.close(); * cf.awaitUninterruptibly(); * bossExecutor.shutdown(); * workerExecutor.shutdown(); * thriftServer.releaseExternalResources(); * </pre> */ } public static final class NorthernerServer { public final ServerBootstrap bootstrap; public final ChannelFuture channelFuture; public NorthernerServer(ServerBootstrap bootstrap, ChannelFuture channelFuture) { this.bootstrap = bootstrap; this.channelFuture = channelFuture; } } }