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

io.hekate.rpc.internal.DefaultRpcClientBuilder Maven / Gradle / Ivy

There is a newer version: 4.1.3
Show newest version
/*
 * Copyright 2020 The Hekate Project
 *
 * The Hekate Project licenses this file to you 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.hekate.rpc.internal;

import io.hekate.cluster.ClusterFilter;
import io.hekate.cluster.ClusterView;
import io.hekate.messaging.MessagingChannel;
import io.hekate.messaging.loadbalance.LoadBalancer;
import io.hekate.messaging.retry.GenericRetryConfigurer;
import io.hekate.partition.PartitionMapper;
import io.hekate.rpc.RpcClientBuilder;
import io.hekate.rpc.RpcInterfaceInfo;
import io.hekate.rpc.RpcLoadBalancer;
import io.hekate.rpc.RpcMethodInfo;
import io.hekate.rpc.RpcRequest;
import io.hekate.rpc.RpcRetryInfo;
import io.hekate.util.format.ToString;
import io.hekate.util.format.ToStringIgnore;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

class DefaultRpcClientBuilder implements RpcClientBuilder {
    private final RpcInterfaceInfo type;

    private final String tag;

    private final long timeout;

    private final GenericRetryConfigurer retry;

    @ToStringIgnore
    private final MessagingChannel channel;

    public DefaultRpcClientBuilder(
        RpcInterfaceInfo type,
        String tag,
        MessagingChannel channel,
        long timeout,
        GenericRetryConfigurer retry
    ) {
        this.type = type;
        this.tag = tag;
        this.channel = channel;
        this.timeout = timeout;
        this.retry = retry;
    }

    @Override
    public RpcClientBuilder withLoadBalancer(RpcLoadBalancer balancer) {
        LoadBalancer rpcBalancer = (message, ctx) -> {
            RpcRequest request = (RpcRequest)message;

            return balancer.route(request, ctx);
        };

        return new DefaultRpcClientBuilder<>(
            type,
            tag,
            channel.withLoadBalancer(rpcBalancer),
            timeout,
            retry
        );
    }

    @Override
    public RpcClientBuilder withRetryPolicy(GenericRetryConfigurer retry) {
        return new DefaultRpcClientBuilder<>(
            type,
            tag,
            channel,
            timeout,
            retry
        );
    }

    @Override
    public long timeout() {
        return timeout;
    }

    @Override
    public RpcClientBuilder withTimeout(long timeout, TimeUnit unit) {
        return new DefaultRpcClientBuilder<>(
            type,
            tag,
            channel,
            unit.toMillis(timeout),
            retry
        );
    }

    @Override
    public RpcClientBuilder filterAll(ClusterFilter filter) {
        return new DefaultRpcClientBuilder<>(
            type,
            tag,
            channel.filterAll(filter),
            timeout,
            retry
        );
    }

    @Override
    public PartitionMapper partitions() {
        return channel.partitions();
    }

    @Override
    public RpcClientBuilder withPartitions(int partitions, int backupNodes) {
        return new DefaultRpcClientBuilder<>(
            type,
            tag,
            channel.withPartitions(partitions, backupNodes),
            timeout,
            retry
        );
    }

    @Override
    public Class type() {
        return type.javaType();
    }

    @Override
    public String tag() {
        return tag;
    }

    @Override
    public ClusterView cluster() {
        return channel.cluster();
    }

    @Override
    public RpcClientBuilder withCluster(ClusterView cluster) {
        return new DefaultRpcClientBuilder<>(
            type,
            tag,
            channel.withCluster(cluster.filter(RpcUtils.filterFor(type, tag))),
            timeout,
            retry
        );
    }

    @Override
    @SuppressWarnings("unchecked")
    public T build() {
        ClassLoader classLoader = type.javaType().getClassLoader();

        Map> clients = new HashMap<>(type.methods().size(), 1.0f);

        for (RpcMethodInfo method : type.methods()) {
            RpcMethodClientBase client;

            if (method.splitArg().isPresent()) {
                client = new RpcSplitAggregateMethodClient<>(type, tag, method, channel, retryPolicy(method), timeout);
            } else if (method.aggregate().isPresent()) {
                client = new RpcAggregateMethodClient<>(type, tag, method, channel, retryPolicy(method), timeout);
            } else if (method.broadcast().isPresent()) {
                client = new RpcBroadcastMethodClient<>(type, tag, method, channel, retryPolicy(method), timeout);
            } else {
                client = new RpcMethodClient<>(type, tag, method, channel, retryPolicy(method), timeout);
            }

            clients.put(method.javaMethod(), client);
        }

        Class[] proxyType = {type.javaType()};

        return (T)Proxy.newProxyInstance(classLoader, proxyType, (proxy, method, args) -> {
            RpcMethodClientBase client = clients.get(method);

            if (client == null) {
                if (method.getDeclaringClass().equals(Object.class)) {
                    return method.invoke(this, args);
                } else {
                    throw new UnsupportedOperationException("Method is not supported by RPC: " + method);
                }
            } else {
                return client.invoke(args);
            }
        });
    }

    private GenericRetryConfigurer retryPolicy(RpcMethodInfo method) {
        if (method.retry().isPresent()) {
            RpcRetryInfo methodRetryPolicy = method.retry().get();

            return retry -> {
                // Apply global policy first.
                if (this.retry != null) {
                    this.retry.configure(retry);
                }

                // Apply the method retry policy.
                methodRetryPolicy.configure(retry);
            };
        } else {
            return null;
        }
    }

    @Override
    public String toString() {
        return ToString.format(this);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy