com.quancheng.saluki.core.grpc.GrpcEngine.java Source code

Java tutorial

Introduction

Here is the source code for com.quancheng.saluki.core.grpc.GrpcEngine.java

Source

/*
 * Copyright (c) 2016, Quancheng-ec.com All right reserved. This software is the
 * confidential and proprietary information of Quancheng-ec.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with Quancheng-ec.com.
 */
package com.quancheng.saluki.core.grpc;

import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import javax.net.ssl.SSLException;

import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.quancheng.saluki.core.common.Constants;
import com.quancheng.saluki.core.common.NamedThreadFactory;
import com.quancheng.saluki.core.common.GrpcURL;
import com.quancheng.saluki.core.grpc.client.GrpcClientStrategy;
import com.quancheng.saluki.core.grpc.client.GrpcProtocolClient;
import com.quancheng.saluki.core.grpc.exception.RpcFrameworkException;
import com.quancheng.saluki.core.grpc.interceptor.HeaderClientInterceptor;
import com.quancheng.saluki.core.grpc.interceptor.HeaderServerInterceptor;
import com.quancheng.saluki.core.grpc.server.GrpcServerStrategy;
import com.quancheng.saluki.core.grpc.util.SslUtil;
import com.quancheng.saluki.core.registry.Registry;
import com.quancheng.saluki.core.registry.RegistryProvider;

import io.grpc.Channel;
import io.grpc.ClientInterceptors;
import io.grpc.Internal;
import io.grpc.LoadBalancer;
import io.grpc.ServerInterceptors;
import io.grpc.ServerServiceDefinition;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;
import io.grpc.netty.NettyServerBuilder;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;

/**
 * @author shimingliu 20161214 ?10:43:19
 * @version GrpcEngine1.java, v 0.0.1 20161214 ?10:43:19 shimingliu
 */
@Internal
public final class GrpcEngine {

    private static final Logger log = LoggerFactory.getLogger(GrpcEngine.class);

    private final GrpcURL registryUrl;

    private final Registry registry;

    private GenericKeyedObjectPool<GrpcURL, Channel> channelPool;

    public GrpcEngine(GrpcURL registryUrl) {
        this.registryUrl = registryUrl;
        this.registry = RegistryProvider.asFactory().newRegistry(registryUrl);
    }

    private void initChannelPool() {
        GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
        config.setMaxTotal(1000);
        config.setMaxTotalPerKey(3);
        config.setBlockWhenExhausted(true);
        config.setMinIdlePerKey(3);
        config.setMaxWaitMillis(10);
        config.setNumTestsPerEvictionRun(Integer.MAX_VALUE);
        config.setTestOnBorrow(false);
        config.setTestOnReturn(false);
        config.setTestWhileIdle(false);
        config.setTimeBetweenEvictionRunsMillis(1 * 60000L);
        config.setMinEvictableIdleTimeMillis(10 * 60000L);
        config.setTestWhileIdle(false);
        this.channelPool = new GenericKeyedObjectPool<GrpcURL, Channel>(new GrpcChannelFactory(), config);
    }

    public Object getClient(GrpcURL refUrl) throws Exception {
        if (channelPool == null) {
            initChannelPool();
        }
        GrpcProtocolClient.ChannelPool hannelPool = new GrpcProtocolClient.ChannelPool() {

            @Override
            public Channel borrowChannel(final GrpcURL realRefUrl) {
                GrpcURL realRefUrltemp = realRefUrl;
                if (realRefUrltemp == null) {
                    realRefUrltemp = refUrl;
                }
                try {
                    return channelPool.borrowObject(realRefUrltemp);
                } catch (Exception e) {
                    throw new java.lang.IllegalArgumentException("Grpc borrow Channel failed", e);
                }
            }

            @Override
            public void returnChannel(final GrpcURL realRefUrl, final Channel channel) {
                GrpcURL realRefUrltemp = realRefUrl;
                if (realRefUrltemp == null) {
                    realRefUrltemp = refUrl;
                }
                channelPool.returnObject(realRefUrltemp, channel);
            }

        };
        GrpcClientStrategy strategy = new GrpcClientStrategy(refUrl, hannelPool);
        return strategy.getGrpcClient();
    }

    public io.grpc.Server getServer(Map<GrpcURL, Object> providerUrls, int rpcPort) throws Exception {

        final NettyServerBuilder remoteServer = NettyServerBuilder.forPort(rpcPort)//
                .sslContext(buildServerSslContext())//
                .bossEventLoopGroup(createBossEventLoopGroup())//
                .workerEventLoopGroup(createWorkEventLoopGroup());
        for (Map.Entry<GrpcURL, Object> entry : providerUrls.entrySet()) {
            GrpcURL providerUrl = entry.getKey();
            Object protocolImpl = entry.getValue();
            GrpcServerStrategy strategy = new GrpcServerStrategy(providerUrl, protocolImpl);
            ServerServiceDefinition serviceDefinition = ServerInterceptors.intercept(strategy.getServerDefintion(),
                    new HeaderServerInterceptor());
            remoteServer.addService(serviceDefinition);
            int registryRpcPort = providerUrl.getParameter(Constants.REGISTRY_RPC_PORT_KEY, rpcPort);
            providerUrl = providerUrl.setPort(registryRpcPort);
            registry.register(providerUrl);
        }
        log.info("grpc server is build complete ");
        return remoteServer.build();

    }

    private SslContext buildClientSslContext() {
        try {
            InputStream certs = SslUtil.loadInputStreamCert("server.pem");
            return GrpcSslContexts.configure(SslContextBuilder.forClient()//
                    .trustManager(certs))//
                    .build();
        } catch (SSLException e) {
            throw new RpcFrameworkException(e);
        }
    }

    private LoadBalancer.Factory buildLoadBalanceFactory() {
        return GrpcRoundRobinLoadBalanceFactory.getInstance();
    }

    private SslContext buildServerSslContext() {
        try {
            InputStream certs = SslUtil.loadInputStreamCert("server.pem");
            InputStream keys = SslUtil.loadInputStreamCert("server_pkcs8.key");
            return GrpcSslContexts.configure(SslContextBuilder.forServer(certs, keys)).build();
        } catch (SSLException e) {
            throw new RpcFrameworkException(e);
        }
    }

    private NioEventLoopGroup createBossEventLoopGroup() {
        ThreadFactory threadFactory = new NamedThreadFactory("grpc-default-boss-ELG", true);
        return new NioEventLoopGroup(1, Executors.newCachedThreadPool(threadFactory));
    }

    private NioEventLoopGroup createWorkEventLoopGroup() {
        ThreadFactory threadFactory = new NamedThreadFactory("grpc-default-worker-ELG", true);
        return new NioEventLoopGroup(0, Executors.newCachedThreadPool(threadFactory));
    }

    private class GrpcChannelFactory extends BaseKeyedPooledObjectFactory<GrpcURL, Channel> {

        @Override
        public Channel create(GrpcURL refURL) throws Exception {
            Channel channel = NettyChannelBuilder.forTarget(registryUrl.toJavaURI().toString())//
                    .nameResolverFactory(new GrpcNameResolverProvider(refURL))//
                    .loadBalancerFactory(buildLoadBalanceFactory())//
                    .sslContext(buildClientSslContext())//
                    .usePlaintext(false)//
                    .negotiationType(NegotiationType.TLS)//
                    .eventLoopGroup(createWorkEventLoopGroup())//
                    .build();//
            return ClientInterceptors.intercept(channel, new HeaderClientInterceptor());
        }

        @Override
        public PooledObject<Channel> wrap(Channel value) {
            return new DefaultPooledObject<Channel>(value);
        }

    }
}