net.devh.boot.grpc.client.channelfactory.NettyChannelFactory.java Source code

Java tutorial

Introduction

Here is the source code for net.devh.boot.grpc.client.channelfactory.NettyChannelFactory.java

Source

/*
 * Copyright (c) 2016-2018 Michael Zhang <yidongnan@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package net.devh.boot.grpc.client.channelfactory;

import static java.util.Objects.requireNonNull;

import java.io.File;
import java.util.List;

import javax.net.ssl.SSLException;

import io.grpc.LoadBalancer;
import io.grpc.NameResolver;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NettyChannelBuilder;
import io.netty.handler.ssl.SslContextBuilder;
import net.devh.boot.grpc.client.config.GrpcChannelProperties;
import net.devh.boot.grpc.client.config.GrpcChannelProperties.Security;
import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
import net.devh.boot.grpc.client.config.NegotiationType;
import net.devh.boot.grpc.client.interceptor.GlobalClientInterceptorRegistry;

/**
 * This channel factory creates and manages netty based {@link GrpcChannelFactory}s.
 *
 * <p>
 * This class utilizes connection pooling and thus needs to be {@link #close() closed} after usage.
 * </p>
 *
 * @author Michael (yidongnan@gmail.com)
 * @author Daniel Theuke (daniel.theuke@heuboe.de)
 * @since 5/17/16
 */
public class NettyChannelFactory extends AbstractChannelFactory<NettyChannelBuilder> {

    private final LoadBalancer.Factory loadBalancerFactory;
    private final NameResolver.Factory nameResolverFactory;

    /**
     * Creates a new GrpcChannelFactory for netty with the given options.
     *
     * @param properties The properties for the channels to create.
     * @param loadBalancerFactory The load balancer factory to use.
     * @param nameResolverFactory The name resolver factory to use.
     * @param globalClientInterceptorRegistry The interceptor registry to use.
     * @param channelConfigurers The channel configurers to use. Can be empty.
     */
    public NettyChannelFactory(final GrpcChannelsProperties properties,
            final LoadBalancer.Factory loadBalancerFactory, final NameResolver.Factory nameResolverFactory,
            final GlobalClientInterceptorRegistry globalClientInterceptorRegistry,
            final List<GrpcChannelConfigurer> channelConfigurers) {
        super(properties, globalClientInterceptorRegistry, channelConfigurers);
        this.loadBalancerFactory = requireNonNull(loadBalancerFactory, "loadBalancerFactory");
        this.nameResolverFactory = requireNonNull(nameResolverFactory, "nameResolverFactory");
    }

    @Override
    @SuppressWarnings("deprecation")
    // TODO: Remove the #loadBalancerFactory() call and replace it with a string property
    // This would break grpc compatibility with pre 1.18 versions.
    protected NettyChannelBuilder newChannelBuilder(final String name) {
        return NettyChannelBuilder.forTarget(name).loadBalancerFactory(this.loadBalancerFactory)
                .nameResolverFactory(this.nameResolverFactory);
    }

    @Override
    // Keep this in sync with ShadedNettyChannelFactory#configureSecurity
    protected void configureSecurity(final NettyChannelBuilder builder, final String name) {
        final GrpcChannelProperties properties = getPropertiesFor(name);

        final NegotiationType negotiationType = properties.getNegotiationType();
        builder.negotiationType(of(negotiationType));

        if (negotiationType == NegotiationType.TLS) {
            final Security security = properties.getSecurity();

            final String authorityOverwrite = security.getAuthorityOverride();
            if (authorityOverwrite != null && !authorityOverwrite.isEmpty()) {
                builder.overrideAuthority(authorityOverwrite);
            }

            final SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient();

            if (security.isClientAuthEnabled()) {
                final File keyCertChainFile = toCheckedFile("keyCertChain", security.getCertificateChainPath());
                final File privateKeyFile = toCheckedFile("privateKey", security.getPrivateKeyPath());
                sslContextBuilder.keyManager(keyCertChainFile, privateKeyFile);
            }

            final String trustCertCollectionPath = security.getTrustCertCollectionPath();
            if (trustCertCollectionPath != null && !trustCertCollectionPath.isEmpty()) {
                final File trustCertCollectionFile = toCheckedFile("trustCertCollection", trustCertCollectionPath);
                sslContextBuilder.trustManager(trustCertCollectionFile);
            }

            try {
                builder.sslContext(sslContextBuilder.build());
            } catch (final SSLException e) {
                throw new IllegalStateException("Failed to create ssl context for grpc client", e);
            }
        }
    }

    /**
     * Converts the given negotiation type to netty's negotiation type.
     *
     * @param negotiationType The negotiation type to convert.
     * @return The converted negotiation type.
     */
    protected static io.grpc.netty.NegotiationType of(final NegotiationType negotiationType) {
        switch (negotiationType) {
        case PLAINTEXT:
            return io.grpc.netty.NegotiationType.PLAINTEXT;
        case PLAINTEXT_UPGRADE:
            return io.grpc.netty.NegotiationType.PLAINTEXT_UPGRADE;
        case TLS:
            return io.grpc.netty.NegotiationType.TLS;
        default:
            throw new IllegalArgumentException("Unsupported NegotiationType: " + negotiationType);
        }
    }

}