sailfish.remoting.channel.AbstractExchangeChannel.java Source code

Java tutorial

Introduction

Here is the source code for sailfish.remoting.channel.AbstractExchangeChannel.java

Source

/**
 *
 *   Copyright 2016-2016 spccold
 *
 *   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 sailfish.remoting.channel;

import java.net.SocketAddress;
import java.util.UUID;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import sailfish.remoting.RequestControl;
import sailfish.remoting.ResponseCallback;
import sailfish.remoting.exceptions.ExceptionCode;
import sailfish.remoting.exceptions.SailfishException;
import sailfish.remoting.future.BytesResponseFuture;
import sailfish.remoting.future.ResponseFuture;
import sailfish.remoting.protocol.RequestProtocol;
import sailfish.remoting.protocol.ResponseProtocol;

/**
 * @author spccold
 * @version $Id: AbstractExchangeChannel.java, v 0.1 20161121 ?10:49:12 spccold Exp $
 */
public abstract class AbstractExchangeChannel implements ExchangeChannel {
    /** underlying channel */
    protected volatile Channel channel;
    protected volatile boolean closed = false;

    private final ExchangeChannelGroup parent;

    protected AbstractExchangeChannel(ExchangeChannelGroup parent) {
        this.parent = parent;
    }

    @Override
    public ExchangeChannelGroup parent() {
        return parent;
    }

    @Override
    public ExchangeChannel next() {
        return this;
    }

    @Override
    public UUID id() {
        return null;
    }

    @Override
    public SocketAddress localAddress() {
        if (null == channel) {
            return null;
        }
        return channel.localAddress();
    }

    @Override
    public SocketAddress remoteAdress() {
        if (null == channel) {
            return null;
        }
        return channel.remoteAddress();
    }

    @Override
    public boolean isAvailable() {
        return null != channel && channel.isOpen() && channel.isActive();
    }

    protected boolean isWritable() {
        return (null != channel && channel.isWritable());
    }

    @Override
    public void close() {
        close(0);
    }

    @Override
    public boolean isClosed() {
        return closed;
    }

    @Override
    public void oneway(byte[] data, RequestControl requestControl) throws SailfishException {
        RequestProtocol protocol = RequestProtocol.newRequest(requestControl);
        protocol.oneway(true);
        protocol.body(data);

        if (requestControl.preferHighPerformanceWriter()) {
            HighPerformanceChannelWriter.write(channel, protocol);
            return;
        }

        if (requestControl.sent() && requestControl.timeout() > 0) {
            ChannelFuture future = channel.writeAndFlush(protocol);
            waitWriteDone(future, requestControl.timeout(), protocol, false);
            return;
        }
        // reduce memory consumption
        channel.writeAndFlush(protocol, channel.voidPromise());
    }

    @Override
    public ResponseFuture<byte[]> request(byte[] data, RequestControl requestControl) throws SailfishException {
        return requestWithFuture(data, null, requestControl);
    }

    @Override
    public void request(byte[] data, ResponseCallback<byte[]> callback, RequestControl requestControl)
            throws SailfishException {
        requestWithFuture(data, callback, requestControl);
    }

    @Override
    public void response(ResponseProtocol response) throws SailfishException {
        channel.writeAndFlush(response, channel.voidPromise());
    }

    private ResponseFuture<byte[]> requestWithFuture(byte[] data, ResponseCallback<byte[]> callback,
            RequestControl requestControl) throws SailfishException {
        final RequestProtocol protocol = RequestProtocol.newRequest(requestControl);
        protocol.oneway(false);
        protocol.body(data);

        ResponseFuture<byte[]> respFuture = new BytesResponseFuture(protocol.packetId(), getTracer());
        respFuture.setCallback(callback, requestControl.timeout());
        // trace before write
        getTracer().trace(this, protocol.packetId(), respFuture);

        if (requestControl.preferHighPerformanceWriter()) {
            HighPerformanceChannelWriter.write(channel, protocol);
            return respFuture;
        }

        if (requestControl.sent()) {
            ChannelFuture future = channel.writeAndFlush(protocol);
            waitWriteDone(future, requestControl.timeout(), protocol, true);
            return respFuture;
        }

        channel.writeAndFlush(protocol, channel.voidPromise());
        return respFuture;
    }

    private void waitWriteDone(ChannelFuture future, int timeout, RequestProtocol request, boolean needRemoveTrace)
            throws SailfishException {
        boolean done = future.awaitUninterruptibly(timeout);
        if (!done) {
            // useless at most of time when do writeAndFlush(...) invoke
            future.cancel(true);
            if (needRemoveTrace) {
                getTracer().remove(request.packetId());
            }
            throw new SailfishException(ExceptionCode.WRITE_TIMEOUT,
                    String.format("write to remote[%s] timeout, protocol[%s]", channel.remoteAddress(), request));
        }
        if (!future.isSuccess()) {
            if (needRemoveTrace) {
                getTracer().remove(request.packetId());
            }
            throw new SailfishException(ExceptionCode.CHANNEL_WRITE_FAIL,
                    String.format("write to remote[%s] fail, protocol[%s]", channel.remoteAddress(), request),
                    future.cause());
        }
    }
}