Skip to content
Snippets Groups Projects
chain.go 3.08 KiB
Newer Older
邹毅贤's avatar
邹毅贤 committed
/*
 * 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 chain

邹毅贤's avatar
邹毅贤 committed
import (
	"sort"
)

import (
	perrors "github.com/pkg/errors"
)

邹毅贤's avatar
邹毅贤 committed
import (
	"github.com/apache/dubbo-go/cluster/router"
	"github.com/apache/dubbo-go/common"
	"github.com/apache/dubbo-go/common/extension"
	"github.com/apache/dubbo-go/common/logger"
	"github.com/apache/dubbo-go/protocol"
)

// RouterChain Router chain
邹毅贤's avatar
邹毅贤 committed
type RouterChain struct {
邹毅贤's avatar
邹毅贤 committed
	//full list of addresses from registry, classified by method name.
	invokers []protocol.Invoker
	//containing all routers, reconstruct every time 'route://' urls change.
	routers []router.Router
	// Fixed router instances: ConfigConditionRouter, TagRouter, e.g., the rule for each instance may change but the
	// instance will never delete or recreate.
	builtinRouters []router.Router
}

邹毅贤's avatar
邹毅贤 committed
func (c RouterChain) Route(invoker []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
邹毅贤's avatar
邹毅贤 committed
	finalInvokers := invoker
	for _, r := range c.routers {
		finalInvokers = r.Route(invoker, url, invocation)
	}
	return finalInvokers
}
邹毅贤's avatar
邹毅贤 committed
func (c RouterChain) AddRouters(routers []router.Router) {
邹毅贤's avatar
邹毅贤 committed
	newRouters := make([]router.Router, 0, len(c.builtinRouters)+len(routers))
邹毅贤's avatar
邹毅贤 committed
	newRouters = append(newRouters, c.builtinRouters...)
	newRouters = append(newRouters, routers...)
	sortRouter(newRouters)
	c.routers = newRouters
}

邹毅贤's avatar
邹毅贤 committed
func NewRouterChain(url *common.URL) (*RouterChain, error) {
邹毅贤's avatar
邹毅贤 committed
	routerFactories := extension.GetRouters()
	if len(routerFactories) == 0 {
邹毅贤's avatar
邹毅贤 committed
		return nil, perrors.Errorf("Illegal route rule!")
邹毅贤's avatar
邹毅贤 committed
	}
邹毅贤's avatar
邹毅贤 committed
	routers := make([]router.Router, 0, len(routerFactories))
邹毅贤's avatar
邹毅贤 committed
	for key, routerFactory := range routerFactories {
邹毅贤's avatar
邹毅贤 committed
		r, err := routerFactory().Router(url)
		if r == nil || err != nil {
邹毅贤's avatar
邹毅贤 committed
			logger.Errorf("router chain build router fail! routerFactories key:%s  error:%s", key, err.Error())
邹毅贤's avatar
邹毅贤 committed
			continue
		}
		routers = append(routers, r)
	}

	newRouters := make([]router.Router, len(routers))
	copy(newRouters, routers)

	sortRouter(newRouters)

邹毅贤's avatar
邹毅贤 committed
	chain := &RouterChain{
邹毅贤's avatar
邹毅贤 committed
		builtinRouters: routers,
		routers:        newRouters,
	}

邹毅贤's avatar
邹毅贤 committed
	return chain, nil
邹毅贤's avatar
邹毅贤 committed
}

func sortRouter(routers []router.Router) {
	sort.Stable(ByPriority(routers))
}

type ByPriority []router.Router

func (a ByPriority) Len() int           { return len(a) }
func (a ByPriority) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByPriority) Less(i, j int) bool { return a[i].Priority() < a[j].Priority() }