blob: 93c0ce6a6692193e7ea7b1b9f2f74e9eaed0c858 [file] [log] [blame]
/*
* 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 config
import (
"bytes"
"reflect"
"strconv"
"strings"
)
import (
perrors "github.com/pkg/errors"
)
import (
"github.com/apache/dubbo-go/common"
"github.com/apache/dubbo-go/common/config"
"github.com/apache/dubbo-go/common/extension"
"github.com/apache/dubbo-go/common/logger"
"github.com/apache/dubbo-go/config_center"
)
type multiConfiger interface {
Prefix() string
}
// BaseConfig is the common configuration for provider and consumer
type BaseConfig struct {
ConfigCenterConfig *ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"`
configCenterUrl *common.URL
prefix string
fatherConfig interface{}
MetricConfig *MetricConfig `yaml:"metrics" json:"metrics,omitempty"`
fileStream *bytes.Buffer
}
// startConfigCenter will start the config center.
// it will prepare the environment
func (c *BaseConfig) startConfigCenter() error {
url, err := common.NewURL(c.ConfigCenterConfig.Address,
common.WithProtocol(c.ConfigCenterConfig.Protocol), common.WithParams(c.ConfigCenterConfig.GetUrlMap()))
if err != nil {
return err
}
c.configCenterUrl = &url
if c.prepareEnvironment() != nil {
return perrors.WithMessagef(err, "start config center error!")
}
//c.fresh()
return err
}
func (c *BaseConfig) prepareEnvironment() error {
factory := extension.GetConfigCenterFactory(c.ConfigCenterConfig.Protocol)
dynamicConfig, err := factory.GetDynamicConfiguration(c.configCenterUrl)
config.GetEnvInstance().SetDynamicConfiguration(dynamicConfig)
if err != nil {
logger.Errorf("Get dynamic configuration error , error message is %v", err)
return perrors.WithStack(err)
}
content, err := dynamicConfig.GetProperties(c.ConfigCenterConfig.ConfigFile, config_center.WithGroup(c.ConfigCenterConfig.Group))
if err != nil {
logger.Errorf("Get config content in dynamic configuration error , error message is %v", err)
return perrors.WithStack(err)
}
var appGroup string
var appContent string
if providerConfig != nil && providerConfig.ApplicationConfig != nil &&
reflect.ValueOf(c.fatherConfig).Elem().Type().Name() == "ProviderConfig" {
appGroup = providerConfig.ApplicationConfig.Name
} else if consumerConfig != nil && consumerConfig.ApplicationConfig != nil &&
reflect.ValueOf(c.fatherConfig).Elem().Type().Name() == "ConsumerConfig" {
appGroup = consumerConfig.ApplicationConfig.Name
}
if len(appGroup) != 0 {
configFile := c.ConfigCenterConfig.AppConfigFile
if len(configFile) == 0 {
configFile = c.ConfigCenterConfig.ConfigFile
}
appContent, err = dynamicConfig.GetProperties(configFile, config_center.WithGroup(appGroup))
if err != nil {
return perrors.WithStack(err)
}
}
//global config file
mapContent, err := dynamicConfig.Parser().Parse(content)
if err != nil {
return perrors.WithStack(err)
}
config.GetEnvInstance().UpdateExternalConfigMap(mapContent)
//appGroup config file
if len(appContent) != 0 {
appMapConent, err := dynamicConfig.Parser().Parse(appContent)
if err != nil {
return perrors.WithStack(err)
}
config.GetEnvInstance().UpdateAppExternalConfigMap(appMapConent)
}
return nil
}
func getKeyPrefix(val reflect.Value) []string {
var (
prefix string
)
if val.CanAddr() {
prefix = val.Addr().MethodByName("Prefix").Call(nil)[0].String()
} else {
prefix = val.MethodByName("Prefix").Call(nil)[0].String()
}
var retPrefixs []string
for _, pfx := range strings.Split(prefix, "|") {
retPrefixs = append(retPrefixs, pfx)
}
return retPrefixs
}
func getPtrElement(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr {
v = v.Elem()
if v.Kind() == reflect.Ptr {
return getPtrElement(v)
}
}
return v
}
func setFieldValue(val reflect.Value, id reflect.Value, config *config.InmemoryConfiguration) {
for i := 0; i < val.NumField(); i++ {
if key := val.Type().Field(i).Tag.Get("property"); key != "-" && key != "" {
f := val.Field(i)
if f.IsValid() {
setBaseValue := func(f reflect.Value) {
var (
ok bool
value string
idStr string
)
prefixs := getKeyPrefix(val)
if id.Kind() == reflect.String {
idStr = id.Interface().(string)
}
for _, pfx := range prefixs {
if len(pfx) > 0 {
if len(idStr) > 0 {
ok, value = config.GetProperty(pfx + idStr + "." + key)
}
if len(value) == 0 || !ok {
ok, value = config.GetProperty(pfx + key)
}
} else {
ok, value = config.GetProperty(key)
}
if ok {
break
}
}
if ok {
switch f.Kind() {
case reflect.Int64:
x, err := strconv.Atoi(value)
if err != nil {
logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
val.Type().Name(), val.Type().Field(i).Name, err)
} else {
if !f.OverflowInt(int64(x)) {
f.SetInt(int64(x))
} else {
logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
val.Type().Name(), val.Type().Field(i).Name, perrors.Errorf("the int64 value {%v} from config center is overflow", int64(x)))
}
}
case reflect.String:
f.SetString(value)
case reflect.Bool:
x, err := strconv.ParseBool(value)
if err != nil {
logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
val.Type().Name(), val.Type().Field(i).Name, err)
}
f.SetBool(x)
case reflect.Float64:
x, err := strconv.ParseFloat(value, 64)
if err != nil {
logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
val.Type().Name(), val.Type().Field(i).Name, err)
} else {
if !f.OverflowFloat(x) {
f.SetFloat(x)
} else {
logger.Errorf("Dynamic change the configuration in struct {%v} field {%v} error ,error message is {%v}",
val.Type().Name(), val.Type().Field(i).Name, perrors.Errorf("the float64 value {%v} from config center is overflow", x))
}
}
default:
logger.Warnf("The kind of field {%v} is not supported ", f.Kind().String())
}
}
}
if f.Kind() == reflect.Ptr {
f = getPtrElement(f)
if f.Kind() == reflect.Struct {
setFieldValue(f, reflect.Value{}, config)
} else {
setBaseValue(f)
}
}
if f.Kind() == reflect.Struct {
setFieldValue(f, reflect.Value{}, config)
}
if f.Kind() == reflect.Slice {
for i := 0; i < f.Len(); i++ {
e := f.Index(i)
if e.Kind() == reflect.Ptr {
e = getPtrElement(e)
if e.Kind() == reflect.Struct {
setFieldValue(e, reflect.Value{}, config)
} else {
setBaseValue(e)
}
}
}
}
if f.Kind() == reflect.Map {
if f.Type().Elem().Kind() == reflect.Ptr {
//initiate config
s := reflect.New(f.Type().Elem().Elem())
prefix := s.MethodByName("Prefix").Call(nil)[0].String()
for _, pfx := range strings.Split(prefix, "|") {
m := config.GetSubProperty(pfx)
if m != nil {
for k := range m {
f.SetMapIndex(reflect.ValueOf(k), reflect.New(f.Type().Elem().Elem()))
}
}
}
}
//iter := f.MapRange()
for _, k := range f.MapKeys() {
v := f.MapIndex(k)
switch v.Kind() {
case reflect.Ptr:
v = getPtrElement(v)
if v.Kind() == reflect.Struct {
setFieldValue(v, k, config)
} else {
setBaseValue(v)
}
case reflect.Int64, reflect.String, reflect.Bool, reflect.Float64:
setBaseValue(v)
default:
logger.Warnf("The kind of field {%v} is not supported ", v.Kind().String())
}
}
}
setBaseValue(f)
}
}
}
}
func (c *BaseConfig) fresh() {
configList := config.GetEnvInstance().Configuration()
for element := configList.Front(); element != nil; element = element.Next() {
cfg := element.Value.(*config.InmemoryConfiguration)
c.freshInternalConfig(cfg)
}
}
func (c *BaseConfig) freshInternalConfig(config *config.InmemoryConfiguration) {
//reflect to init struct
tp := reflect.ValueOf(c.fatherConfig).Elem().Type()
initializeStruct(tp, reflect.ValueOf(c.fatherConfig).Elem())
val := reflect.Indirect(reflect.ValueOf(c.fatherConfig))
setFieldValue(val, reflect.Value{}, config)
}
// SetFatherConfig ...
func (c *BaseConfig) SetFatherConfig(fatherConfig interface{}) {
c.fatherConfig = fatherConfig
}
func initializeStruct(t reflect.Type, v reflect.Value) {
if v.Kind() == reflect.Struct {
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
ft := t.Field(i)
if ft.Tag.Get("property") != "" {
switch ft.Type.Kind() {
case reflect.Map:
if f.IsNil() {
f.Set(reflect.MakeMap(ft.Type))
}
case reflect.Slice:
if f.IsNil() {
f.Set(reflect.MakeSlice(ft.Type, 0, 0))
}
case reflect.Chan:
if f.IsNil() {
f.Set(reflect.MakeChan(ft.Type, 0))
}
case reflect.Struct:
if f.IsNil() {
initializeStruct(ft.Type, f)
}
case reflect.Ptr:
if f.IsNil() {
fv := reflect.New(ft.Type.Elem())
initializeStruct(ft.Type.Elem(), fv.Elem())
f.Set(fv)
}
default:
}
}
}
}
}