Java tutorial
/* * Copyright (c) 2014 koiroha.org. * All sources and related resources are available under Apache License 2.0. * http://www.apache.org/licenses/LICENSE-2.0.html */ package org.asterisque.netty; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.ssl.SslHandler; import org.asterisque.Asterisque; import org.asterisque.Debug; import org.asterisque.Node; import org.asterisque.Options; import org.asterisque.msg.Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLSession; import java.io.IOException; import java.net.SocketAddress; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // WireConnect // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ /** * @author Takami Torao */ class WireConnect extends SimpleChannelInboundHandler<Message> { private static Logger logger = LoggerFactory.getLogger(WireConnect.class); /** * WireConnect ? ID ?????????????????????? */ private static final AtomicInteger Sequence = new AtomicInteger(0); private final Node node; private final SocketAddress local; private final SocketAddress remote; private final Options options; private final Optional<SslHandler> sslHandler; private final boolean isServer; private final Consumer<NettyWire> onWireCreate; private final String sym; /** * ??? Wire */ private volatile Optional<NettyWire> wire = Optional.empty(); /** * ? Wire ????? ID ? */ private final int id = Sequence.getAndIncrement() & 0x7FFFFFFF; // ============================================================================================== // // ============================================================================================== /** */ public WireConnect(Node node, SocketAddress local, SocketAddress remote, boolean isServer, Optional<SslHandler> sslHandler, Consumer<NettyWire> onWireCreate, Options options) { super(Message.class); this.node = node; this.local = local; this.remote = remote; this.sslHandler = sslHandler; this.isServer = isServer; this.onWireCreate = onWireCreate; this.options = options; this.sym = isServer ? "S" : "C"; } // ============================================================================================== // ??? // ============================================================================================== /** * ??????????? * SSL ?????? * @param ctx */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { trace("channelActive(" + ctx.name() + ")"); assert (!wire.isPresent()); // SSLHandler ???????? SSLSession ? CompletableFuture<Optional<SSLSession>> future = new CompletableFuture<>(); if (sslHandler.isPresent()) { SslHandler h = sslHandler.get(); h.handshakeFuture().addListener(f -> { SSLSession session = h.engine().getSession(); if (session.isValid()) { // SSL ? future.complete(Optional.of(session)); debug("tls handshake success"); } else { // SSL ? future.completeExceptionally(new IOException("tls handshake failure: invalid session")); debug("tls handshake failure: invalid session"); } Debug.dumpSSLSession(logger, sym + "[" + id + "]", session); }); } else { // SSL ?? future.complete(Optional.empty()); } // Wire NettyWire w = new NettyWire(node, local, remote, isServer, future, ctx); wire = Optional.of(w); super.channelActive(ctx); // onWireCreate.accept(w); } // ============================================================================================== // ??? // ============================================================================================== /** * @param ctx */ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { trace("channelInactive(" + ctx.name() + ")"); closeWire(); super.channelInactive(ctx); } // ============================================================================================== // ?? // ============================================================================================== /** * @param ctx * @param msg */ @Override public void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception { trace("channelRead0(" + ctx.name() + "," + msg + ")"); // assert (wire.isPresent()); wire.ifPresent(w -> { w.receive(msg); }); // super.channelRead0(ctx, msg) ? } // ============================================================================================== // ? // ============================================================================================== /** * @param ctx * @param cause ?? */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { logger.debug(id() + ": exception caught", cause); closeWire(); } // ============================================================================================== // ? // ============================================================================================== /** */ private void closeWire() { trace("closeWire()"); if (wire.isPresent()) { wire.get().close(); wire = Optional.empty(); } } private void debug(String log) { if (logger.isDebugEnabled()) { logger.debug(id() + ": " + log); } } private void trace(String log) { if (logger.isTraceEnabled()) { logger.trace(id() + ": " + log); } } public String id() { return wire.map(NettyWire::id).orElse(Asterisque.logPrefix(isServer)); } }