org.asterisque.netty.WireConnect.java Source code

Java tutorial

Introduction

Here is the source code for org.asterisque.netty.WireConnect.java

Source

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

}