All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dongliu.prettypb.rpc.RpcClient Maven / Gradle / Ivy

There is a newer version: 0.3.5
Show newest version
package net.dongliu.prettypb.rpc;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import net.dongliu.prettypb.rpc.client.*;
import net.dongliu.prettypb.rpc.config.ServerChangedNotifier;
import net.dongliu.prettypb.rpc.config.ServerProvider;
import net.dongliu.prettypb.rpc.exception.ServiceException;
import net.dongliu.prettypb.rpc.listener.TcpConnectionEventListener;
import net.dongliu.prettypb.rpc.protocol.RpcRequest;
import net.dongliu.prettypb.rpc.protocol.ServerInfo;
import net.dongliu.prettypb.runtime.ExtensionRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * rpc client
 *
 * @author Dong Liu
 */
public class RpcClient implements AutoCloseable, ServerChangedNotifier {

    private final ServerProvider serverProvider;

    /**
     * if client want to use compress
     */
    private boolean compress;

    /**
     * rpc call time out in milliseconds
     */
    private int timeout = 10_000;

    /**
     * connect to rpc server timeout  in milliseconds
     */
    private int connectTimeout = 30_000;

    /**
     * extension registry for wire payload
     */
    private ExtensionRegistry wpExtensionRegistry;

    /**
     * extension registry for rpc messages
     */
    private ExtensionRegistry extensionRegistry;

    private final AtomicInteger correlationId = new AtomicInteger(1);

    private StubServiceFactory stubServiceFactory;

    private RpcClientChannelGroup rpcClientChannelGroup;

    private Bootstrap bootstrap;

    private static Logger logger = LoggerFactory.getLogger(RpcClient.class);

    /**
     * create a rpc client
     */
    public RpcClient(ServerProvider serverProvider)
            throws InterruptedException, TimeoutException, IOException {
        this.serverProvider = serverProvider;
        this.serverProvider.setServerChangedNotifier(this);
        connect();
    }

    /**
     * connect to rpc server. could also used to reconnect when connection broken
     *
     * @throws IOException
     */
    public void connect() throws IOException, TimeoutException, InterruptedException {
        bootstrap = new Bootstrap();
        bootstrap.group(new NioEventLoopGroup())
                .handler(new ProtobufChannelInitializer(null, wpExtensionRegistry))
                .channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.TCP_NODELAY, true)
                // we use connect time out for this too.
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout)
                .option(ChannelOption.SO_SNDBUF, 1_048_576)
                .option(ChannelOption.SO_RCVBUF, 1_048_576);

        Collection servers = serverProvider.availableServers();
        if (servers == null || servers.isEmpty()) {
            throw new ServiceException("no server found");
        }

        List channels = new ArrayList<>(servers.size());
        for (ServerInfo serverInfo : servers) {
            RpcClientChannel rpcClientChannel = newRpcChannel(serverInfo);
            rpcClientChannel.connect();
            channels.add(rpcClientChannel);
        }
        rpcClientChannelGroup = new RpcClientChannelGroup(channels);

        stubServiceFactory = new StubServiceFactory(correlationId, this);
    }

    private RpcClientChannel newRpcChannel(ServerInfo serverInfo) {
        return new RpcClientChannel(serverInfo, bootstrap, correlationId.getAndIncrement(),
                compress, connectTimeout, Collections.emptyList(),
                extensionRegistry);
    }

    /**
     * get a rpc interface impl powered by rpc server
     *
     * @param interfaceClass the rpc interface class
     * @param             the rpc interface
     * @return
     */
    public  T getService(Class interfaceClass) {
        return stubServiceFactory.getService(interfaceClass, this.timeout);
    }

    /**
     * get a rpc interface impl powered by rpc server with specified rpc timeout.
     * the timeout will shadow the rpc time value set in rpc client
     *
     * @param interfaceClass the rpc interface class
     * @param timeout        the timeout. should larger than 0
     * @param             the rpc interface
     * @return
     */
    public  T getService(Class interfaceClass, int timeout) {
        return stubServiceFactory.getService(interfaceClass, timeout);
    }

    /**
     * close rpc client
     */
    @Override
    public void close() {
        try {
            serverProvider.close();
        } catch (Exception e) {
            logger.error("", e);
        }

        // close channel
        if (rpcClientChannelGroup != null) {
            rpcClientChannelGroup.close();
        }

        try {
            bootstrap.group().shutdownGracefully().sync();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * for internal use only
     */
    public void writeRequest(ClientCallTask task, RpcRequest rpcRequest) {
        RpcClientChannel channel = rpcClientChannelGroup.select();
        channel.writeRequest(task, rpcRequest);
    }

    /**
     * get rpc connect server timeout
     *
     * @return timeout in milliseconds
     */
    public int getConnectTimeout() {
        return connectTimeout;
    }

    /**
     * set rpc connect server timeout. default is 10,000
     *
     * @param connectTimeout timeout in milliseconds. must be large than 0
     * @return
     */
    public RpcClient setConnectTimeout(int connectTimeout) {
        if (connectTimeout <= 0) {
            throw new IllegalArgumentException("Timeout should be larger than 0");
        }
        this.connectTimeout = connectTimeout;
        return this;
    }

    /**
     * get rpc call timeout
     *
     * @return timeout in milliseconds
     */
    public int getTimeout() {
        return timeout;
    }

    /**
     * set time out for rpc call.  default is 30,000
     *
     * @param timeout timeout in milliseconds. must be large than 0
     */
    public void setTimeout(int timeout) {
        if (timeout <= 0) {
            throw new IllegalArgumentException("Timeout should be larger than 0");
        }
        this.timeout = timeout;
    }

    /**
     * set if client want to use zlib compress. default is false.
     * rpc will use compress if both client and server want to use compress
     */
    public RpcClient setCompress(boolean compress) {
        this.compress = compress;
        return this;
    }

    /**
     * if client want to use compress
     */
    public boolean isCompress() {
        return compress;
    }

    /**
     * get wire payload extension registry
     */
    public ExtensionRegistry getWpExtensionRegistry() {
        return wpExtensionRegistry;
    }

    /**
     * set extension registry for wire payload
     */
    public RpcClient setWpExtensionRegistry(ExtensionRegistry wpExtensionRegistry) {
        this.wpExtensionRegistry = wpExtensionRegistry;
        return this;
    }

    /**
     * get rpc message extension registry
     */
    public ExtensionRegistry getExtensionRegistry() {
        return extensionRegistry;
    }

    /**
     * set rpc message extension registry
     */
    public RpcClient setExtensionRegistry(ExtensionRegistry extensionRegistry) {
        this.extensionRegistry = extensionRegistry;
        return this;
    }

    @Override
    public void notifyAdd(ServerInfo serverInfo) {
        RpcClientChannel channel = newRpcChannel(serverInfo);
        this.rpcClientChannelGroup.add(channel);
    }

    @Override
    public void notifyRemove(ServerInfo serverInfo) {
        this.rpcClientChannelGroup.remove(serverInfo);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy