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

org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster Maven / Gradle / Ivy

There is a newer version: 3.3.0-beta.5
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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 org.apache.dubbo.rpc.cluster.support.wrapper;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.ClusterInvoker;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance;
import org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;
import org.apache.dubbo.rpc.cluster.filter.InvocationInterceptorBuilder;
import org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor;
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
import org.apache.dubbo.rpc.model.ScopeModelUtil;

import java.util.List;

import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_INTERCEPTOR_COMPATIBLE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INVOCATION_INTERCEPTOR_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;

public abstract class AbstractCluster implements Cluster {

    private  Invoker buildClusterInterceptors(AbstractClusterInvoker clusterInvoker) {
        AbstractClusterInvoker last = buildInterceptorInvoker(new ClusterFilterInvoker<>(clusterInvoker));

        if (Boolean.parseBoolean(ConfigurationUtils.getProperty(clusterInvoker.getDirectory().getConsumerUrl().getScopeModel(), CLUSTER_INTERCEPTOR_COMPATIBLE_KEY, "false"))) {
            return build27xCompatibleClusterInterceptors(clusterInvoker, last);
        }
        return last;
    }

    @Override
    public  Invoker join(Directory directory, boolean buildFilterChain) throws RpcException {
        if (buildFilterChain) {
            return buildClusterInterceptors(doJoin(directory));
        } else {
            return doJoin(directory);
        }
    }

    private  AbstractClusterInvoker buildInterceptorInvoker(AbstractClusterInvoker invoker) {
        List builders = ScopeModelUtil.getApplicationModel(invoker.getUrl().getScopeModel()).getExtensionLoader(InvocationInterceptorBuilder.class).getActivateExtensions();
        if (CollectionUtils.isEmpty(builders)) {
            return invoker;
        }
        return new InvocationInterceptorInvoker<>(invoker, builders);
    }

    protected abstract  AbstractClusterInvoker doJoin(Directory directory) throws RpcException;

    static class ClusterFilterInvoker extends AbstractClusterInvoker {
        private final ClusterInvoker filterInvoker;

        public ClusterFilterInvoker(AbstractClusterInvoker invoker) {
            List builders = ScopeModelUtil.getApplicationModel(invoker.getUrl().getScopeModel()).getExtensionLoader(FilterChainBuilder.class).getActivateExtensions();
            if (CollectionUtils.isEmpty(builders)) {
                filterInvoker = invoker;
            } else {
                ClusterInvoker tmpInvoker = invoker;
                for (FilterChainBuilder builder : builders) {
                    tmpInvoker = builder.buildClusterInvokerChain(tmpInvoker, REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
                }
                filterInvoker = tmpInvoker;
            }
        }

        @Override
        public Result invoke(Invocation invocation) throws RpcException {
            return filterInvoker.invoke(invocation);
        }

        @Override
        public Directory getDirectory() {
            return filterInvoker.getDirectory();
        }



        @Override
        public URL getRegistryUrl() {
            return filterInvoker.getRegistryUrl();
        }

        @Override
        public boolean isDestroyed() {
            return filterInvoker.isDestroyed();
        }

        @Override
        public URL getUrl() {
            return filterInvoker.getUrl();
        }

        /**
         * The only purpose is to build a interceptor chain, so the cluster related logic doesn't matter.
         * Use ClusterInvoker to replace AbstractClusterInvoker in the future.
         */
        @Override
        protected Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException {
           return null;
        }

        public ClusterInvoker getFilterInvoker() {
            return filterInvoker;
        }
    }

    static class InvocationInterceptorInvoker extends AbstractClusterInvoker {
        private ClusterInvoker interceptorInvoker;

        public InvocationInterceptorInvoker(AbstractClusterInvoker invoker, List builders) {
            ClusterInvoker tmpInvoker = invoker;
            for (InvocationInterceptorBuilder builder : builders) {
                tmpInvoker = builder.buildClusterInterceptorChain(tmpInvoker, INVOCATION_INTERCEPTOR_KEY, CommonConstants.CONSUMER);
            }
            interceptorInvoker = tmpInvoker;
        }

        @Override
        public Result invoke(Invocation invocation) throws RpcException {
            return interceptorInvoker.invoke(invocation);
        }

        @Override
        public Directory getDirectory() {
            return interceptorInvoker.getDirectory();
        }

        @Override
        public URL getRegistryUrl() {
            return interceptorInvoker.getRegistryUrl();
        }

        @Override
        public boolean isDestroyed() {
            return interceptorInvoker.isDestroyed();
        }

        @Override
        public URL getUrl() {
            return interceptorInvoker.getUrl();
        }

        /**
         * The only purpose is to build a interceptor chain, so the cluster related logic doesn't matter.
         * Use ClusterInvoker to replace AbstractClusterInvoker in the future.
         */
        @Override
        protected Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException {
            return null;
        }
    }

    @Deprecated
    private  ClusterInvoker build27xCompatibleClusterInterceptors(AbstractClusterInvoker clusterInvoker, AbstractClusterInvoker last) {
        List interceptors = ScopeModelUtil.getApplicationModel(clusterInvoker.getUrl().getScopeModel()).getExtensionLoader(ClusterInterceptor.class).getActivateExtensions();

        if (!interceptors.isEmpty()) {
            for (int i = interceptors.size() - 1; i >= 0; i--) {
                final ClusterInterceptor interceptor = interceptors.get(i);
                final AbstractClusterInvoker next = last;
                last = new InterceptorInvokerNode<>(clusterInvoker, interceptor, next);
            }
        }
        return last;
    }

    @Deprecated
    static class InterceptorInvokerNode extends AbstractClusterInvoker {

        private final AbstractClusterInvoker clusterInvoker;
        private final ClusterInterceptor interceptor;
        private final AbstractClusterInvoker next;

        public InterceptorInvokerNode(AbstractClusterInvoker clusterInvoker,
                                      ClusterInterceptor interceptor,
                                      AbstractClusterInvoker next) {
            this.clusterInvoker = clusterInvoker;
            this.interceptor = interceptor;
            this.next = next;
        }

        @Override
        public Class getInterface() {
            return clusterInvoker.getInterface();
        }

        @Override
        public URL getUrl() {
            return clusterInvoker.getUrl();
        }

        @Override
        public boolean isAvailable() {
            return clusterInvoker.isAvailable();
        }

        @Override
        public Result invoke(Invocation invocation) throws RpcException {
            Result asyncResult;
            try {
                interceptor.before(next, invocation);
                asyncResult = interceptor.intercept(next, invocation);
            } catch (Exception e) {
                // onError callback
                if (interceptor instanceof ClusterInterceptor.Listener) {
                    ClusterInterceptor.Listener listener = (ClusterInterceptor.Listener) interceptor;
                    listener.onError(e, clusterInvoker, invocation);
                }
                throw e;
            } finally {
                interceptor.after(next, invocation);
            }
            return asyncResult.whenCompleteWithContext((r, t) -> {
                // onResponse callback
                if (interceptor instanceof ClusterInterceptor.Listener) {
                    ClusterInterceptor.Listener listener = (ClusterInterceptor.Listener) interceptor;
                    if (t == null) {
                        listener.onMessage(r, clusterInvoker, invocation);
                    } else {
                        listener.onError(t, clusterInvoker, invocation);
                    }
                }
            });
        }

        @Override
        public void destroy() {
            clusterInvoker.destroy();
        }

        @Override
        public String toString() {
            return clusterInvoker.toString();
        }

        @Override
        protected Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException {
            // The only purpose is to build an interceptor chain, so the cluster related logic doesn't matter.
            return null;
        }
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy