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