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

io.etcd.jetcd.impl.ClientConnectionManager Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016-2021 The jetcd authors
 *
 * 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 io.etcd.jetcd.impl;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;

import io.etcd.jetcd.ByteSequence;
import io.etcd.jetcd.ClientBuilder;
import io.etcd.jetcd.support.Util;
import io.grpc.*;
import io.grpc.ForwardingClientCall.SimpleForwardingClientCall;
import io.grpc.netty.NegotiationType;
import io.grpc.stub.AbstractStub;
import io.netty.channel.ChannelOption;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.grpc.VertxChannelBuilder;

import static io.etcd.jetcd.common.exception.EtcdExceptionFactory.toEtcdException;

final class ClientConnectionManager {
    private final Object lock;
    private final ClientBuilder builder;
    private final ExecutorService executorService;
    private final AuthCredential credential;
    private volatile Vertx vertx;
    private volatile ManagedChannel managedChannel;

    ClientConnectionManager(ClientBuilder builder) {
        this(builder, null);
    }

    ClientConnectionManager(ClientBuilder builder, ManagedChannel managedChannel) {
        this.lock = new Object();
        this.builder = builder;
        this.managedChannel = managedChannel;
        this.credential = new AuthCredential(this);

        if (builder.executorService() == null) {
            // default to daemon
            this.executorService = Executors.newCachedThreadPool(Util.createThreadFactory("jetcd-", true));
        } else {
            this.executorService = builder.executorService();
        }
    }

    ManagedChannel getChannel() {
        if (managedChannel == null) {
            synchronized (lock) {
                if (managedChannel == null) {
                    managedChannel = defaultChannelBuilder().build();
                }
            }
        }

        return managedChannel;
    }

    ByteSequence getNamespace() {
        return builder.namespace();
    }

    ExecutorService getExecutorService() {
        return executorService;
    }

    ClientBuilder builder() {
        return builder;
    }

    AuthCredential authCredential() {
        return this.credential;
    }

    /**
     * create stub with saved channel.
     *
     * @param  supplier the stub supplier
     * @param        the type of stub
     * @return          the attached stub
     */
    > T newStub(Function supplier) {
        return newStub(supplier, getChannel());
    }

    private > T newStub(Function stubCustomizer, ManagedChannel channel) {
        T stub = stubCustomizer.apply(channel);
        if (builder.waitForReady()) {
            stub = stub.withWaitForReady();
        }
        if (builder.user() != null && builder.password() != null) {
            stub = stub.withCallCredentials(this.authCredential());
        }

        return stub;
    }

    void close() {
        synchronized (lock) {
            if (managedChannel != null) {
                managedChannel.shutdownNow();
            }
            if (vertx != null) {
                vertx.close();
            }
        }

        if (builder.executorService() == null) {
            executorService.shutdownNow();
        }
    }

    , R> CompletableFuture withNewChannel(
        String target,
        Function stubCustomizer,
        Function> stubConsumer) {

        final ManagedChannel channel = defaultChannelBuilder(target).build();
        final T stub = newStub(stubCustomizer, channel);

        try {
            return stubConsumer.apply(stub).whenComplete((r, t) -> channel.shutdown());
        } catch (Exception e) {
            channel.shutdown();
            throw toEtcdException(e);
        }
    }

    ManagedChannelBuilder defaultChannelBuilder() {
        return defaultChannelBuilder(builder.target());
    }

    @SuppressWarnings("rawtypes")
    ManagedChannelBuilder defaultChannelBuilder(String target) {
        if (target == null) {
            throw new IllegalArgumentException("At least one endpoint should be provided");
        }

        final VertxChannelBuilder channelBuilder = VertxChannelBuilder.forTarget(vertx(), target);

        if (builder.authority() != null) {
            channelBuilder.overrideAuthority(builder.authority());
        }
        if (builder.maxInboundMessageSize() != null) {
            channelBuilder.maxInboundMessageSize(builder.maxInboundMessageSize());
        }
        if (builder.sslContext() != null) {
            channelBuilder.nettyBuilder().negotiationType(NegotiationType.TLS);
            channelBuilder.nettyBuilder().sslContext(builder.sslContext());
        } else {
            channelBuilder.nettyBuilder().negotiationType(NegotiationType.PLAINTEXT);
        }

        if (builder.keepaliveTime() != null) {
            channelBuilder.keepAliveTime(builder.keepaliveTime().toMillis(), TimeUnit.MILLISECONDS);
        }
        if (builder.keepaliveTimeout() != null) {
            channelBuilder.keepAliveTimeout(builder.keepaliveTimeout().toMillis(), TimeUnit.MILLISECONDS);
        }
        if (builder.keepaliveWithoutCalls() != null) {
            channelBuilder.keepAliveWithoutCalls(builder.keepaliveWithoutCalls());
        }
        if (builder.connectTimeout() != null) {
            channelBuilder.nettyBuilder().withOption(ChannelOption.CONNECT_TIMEOUT_MILLIS,
                (int) builder.connectTimeout().toMillis());
        }

        if (builder.loadBalancerPolicy() != null) {
            channelBuilder.defaultLoadBalancingPolicy(builder.loadBalancerPolicy());
        } else {
            channelBuilder.defaultLoadBalancingPolicy("round_robin");
        }

        if (builder.headers() != null) {
            channelBuilder.intercept(new ClientInterceptor() {
                @Override
                public  ClientCall interceptCall(
                    MethodDescriptor method,
                    CallOptions callOptions,
                    Channel next) {

                    return new SimpleForwardingClientCall(next.newCall(method, callOptions)) {
                        @Override
                        public void start(Listener responseListener, Metadata headers) {
                            builder.headers().forEach((BiConsumer) headers::put);
                            super.start(responseListener, headers);
                        }
                    };
                }
            });
        }

        if (builder.interceptors() != null) {
            channelBuilder.intercept(builder.interceptors());
        }

        return channelBuilder;
    }

    Vertx vertx() {
        if (this.vertx == null) {
            synchronized (this.lock) {
                if (this.vertx == null) {
                    this.vertx = Vertx.vertx(new VertxOptions().setUseDaemonThread(true));
                }
            }
        }

        return this.vertx;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy