Merge pull request #1649 from apache/feat-adasvc

feat: add adaptive service
diff --git a/common/constant/key.go b/common/constant/key.go
index 067ccf0..b896af7 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -210,6 +210,7 @@
 	RouterConfigPrefix         = "dubbo.router"
 	TracingConfigPrefix        = "dubbo.tracing"
 	LoggerConfigPrefix         = "dubbo.logger"
+	CustomConfigPrefix         = "dubbo.custom"
 )
 
 const (
diff --git a/config/custom_config.go b/config/custom_config.go
new file mode 100644
index 0000000..93607ed
--- /dev/null
+++ b/config/custom_config.go
@@ -0,0 +1,80 @@
+/*
+ * 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 (
+	"github.com/creasty/defaults"
+)
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+type CustomConfig struct {
+	ConfigMap map[string]interface{} `yaml:"config-map" json:"config-map,omitempty" property:"config-map"`
+}
+
+func (*CustomConfig) Prefix() string {
+	return constant.CustomConfigPrefix
+}
+
+func (c *CustomConfig) Init() error {
+	return c.check()
+}
+
+func (c *CustomConfig) check() error {
+	if err := defaults.Set(c); err != nil {
+		return err
+	}
+	return verify(c)
+}
+
+func (c *CustomConfig) GetDefineValue(key string, default_value interface{}) interface{} {
+	if define_value, ok := c.ConfigMap[key]; ok {
+		return define_value
+	}
+	return default_value
+}
+
+func GetDefineValue(key string, default_value interface{}) interface{} {
+	rt := GetRootConfig()
+	if rt.Custom == nil {
+		return default_value
+	}
+	return rt.Custom.GetDefineValue(key, default_value)
+}
+
+type CustomConfigBuilder struct {
+	customConfig *CustomConfig
+}
+
+func NewCustomConfigBuilder() *CustomConfigBuilder {
+	return &CustomConfigBuilder{customConfig: &CustomConfig{}}
+}
+
+func (ccb *CustomConfigBuilder) SetDefineConfig(key string, val interface{}) *CustomConfigBuilder {
+	if ccb.customConfig.ConfigMap == nil {
+		ccb.customConfig.ConfigMap = make(map[string]interface{})
+	}
+	ccb.customConfig.ConfigMap[key] = val
+	return ccb
+}
+
+func (ccb *CustomConfigBuilder) Build() *CustomConfig {
+	return ccb.customConfig
+}
diff --git a/config/custom_config_test.go b/config/custom_config_test.go
new file mode 100644
index 0000000..1289584
--- /dev/null
+++ b/config/custom_config_test.go
@@ -0,0 +1,68 @@
+/*
+ * 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 (
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+func TestCustomInit(t *testing.T) {
+	t.Run("empty use default", func(t *testing.T) {
+		err := Load(WithPath("./testdata/config/custom/empty.yaml"))
+		assert.Nil(t, err)
+		assert.NotNil(t, rootConfig)
+		CustomConfig := rootConfig.Custom
+		assert.NotNil(t, CustomConfig)
+		assert.Equal(t, CustomConfig.ConfigMap, map[string]interface{}(nil))
+		assert.Equal(t, CustomConfig.GetDefineValue("test", "test"), "test")
+		assert.Equal(t, GetDefineValue("test", "test"), "test")
+	})
+
+	t.Run("use config", func(t *testing.T) {
+		err := Load(WithPath("./testdata/config/custom/custom.yaml"))
+		assert.Nil(t, err)
+		assert.NotNil(t, rootConfig)
+		CustomConfig := rootConfig.Custom
+		assert.NotNil(t, CustomConfig)
+		assert.Equal(t, CustomConfig.ConfigMap, map[string]interface{}{"test-config": true})
+		assert.Equal(t, CustomConfig.GetDefineValue("test-config", false), true)
+		assert.Equal(t, CustomConfig.GetDefineValue("test-no-config", false), false)
+		assert.Equal(t, GetDefineValue("test-config", false), true)
+		assert.Equal(t, GetDefineValue("test-no-config", false), false)
+	})
+
+	t.Run("config builder", func(t *testing.T) {
+		CustomConfigBuilder := NewCustomConfigBuilder()
+		CustomConfigBuilder.SetDefineConfig("test-build", true)
+		CustomConfig := CustomConfigBuilder.Build()
+		assert.NotNil(t, CustomConfig)
+		assert.Equal(t, CustomConfig.GetDefineValue("test-build", false), true)
+		assert.Equal(t, CustomConfig.GetDefineValue("test-no-build", false), false)
+		// todo @(laurence) now we should guarantee rootConfig ptr can't be changed during test
+		tempRootConfig := rootConfig
+		rt := NewRootConfigBuilder().SetCustom(CustomConfig).Build()
+		SetRootConfig(*rt)
+		assert.Equal(t, GetDefineValue("test-build", false), true)
+		assert.Equal(t, GetDefineValue("test-no-build", false), false)
+		SetRootConfig(*tempRootConfig)
+	})
+}
diff --git a/config/root_config.go b/config/root_config.go
index 3b2e9c7..ad3c33a 100644
--- a/config/root_config.go
+++ b/config/root_config.go
@@ -80,6 +80,8 @@
 
 	// cache file used to store the current used configurations.
 	CacheFile string `yaml:"cache_file" json:"cache_file,omitempty" property:"cache_file"`
+
+	Custom *CustomConfig `yaml:"custom" json:"custom,omitempty" property:"custom"`
 }
 
 func SetRootConfig(r RootConfig) {
@@ -153,6 +155,11 @@
 		return err
 	}
 
+	// init user define
+	if err := rc.Custom.Init(); err != nil {
+		return err
+	}
+
 	// init protocol
 	protocols := rc.Protocols
 	if len(protocols) <= 0 {
@@ -226,6 +233,7 @@
 		Consumer:       NewConsumerConfigBuilder().Build(),
 		Metric:         NewMetricConfigBuilder().Build(),
 		Logger:         NewLoggerConfigBuilder().Build(),
+		Custom:         NewCustomConfigBuilder().Build(),
 	}
 	return newRootConfig
 }
@@ -313,6 +321,11 @@
 	return rb
 }
 
+func (rb *RootConfigBuilder) SetCustom(customConfig *CustomConfig) *RootConfigBuilder {
+	rb.rootConfig.Custom = customConfig
+	return rb
+}
+
 func (rb *RootConfigBuilder) Build() *RootConfig {
 	return rb.rootConfig
 }
diff --git a/config/testdata/config/custom/custom.yaml b/config/testdata/config/custom/custom.yaml
new file mode 100644
index 0000000..6129796
--- /dev/null
+++ b/config/testdata/config/custom/custom.yaml
@@ -0,0 +1,13 @@
+dubbo:
+  registries:
+    nacos:
+      timeout: 5s
+      group: dev
+      address: nacos://127.0.0.1:8848
+    zk:
+      protocol: zookeeper
+      group: test
+      address: 127.0.0.1:2181
+  custom:
+    config-map:
+      test-config: true
diff --git a/config/testdata/config/custom/empty.yaml b/config/testdata/config/custom/empty.yaml
new file mode 100644
index 0000000..a4611db
--- /dev/null
+++ b/config/testdata/config/custom/empty.yaml
@@ -0,0 +1,11 @@
+dubbo:
+  custom:
+  registries:
+    nacos:
+      timeout: 5s
+      group: dev
+      address: nacos://127.0.0.1:8848
+    zk:
+      protocol: zookeeper
+      group: test
+      address: 127.0.0.1:2181
diff --git a/go.mod b/go.mod
index fb623cd..8319c96 100644
--- a/go.mod
+++ b/go.mod
@@ -34,7 +34,7 @@
 	github.com/natefinch/lumberjack v2.0.0+incompatible
 	github.com/opentracing/opentracing-go v1.2.0
 	github.com/pkg/errors v0.9.1
-	github.com/polarismesh/polaris-go v1.0.0
+	github.com/polarismesh/polaris-go v1.0.1
 	github.com/prometheus/client_golang v1.11.0
 	github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
 	github.com/stretchr/testify v1.7.0
diff --git a/go.sum b/go.sum
index a2b8297..0abe072 100644
--- a/go.sum
+++ b/go.sum
@@ -66,8 +66,8 @@
 github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw=
 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
-github.com/agiledragon/gomonkey v0.0.0-20190517145658-8fa491f7b918 h1:a88Ln+jbIokfi6xoKtq10dbgp4VMg1CmHF1J42p8EyE=
-github.com/agiledragon/gomonkey v0.0.0-20190517145658-8fa491f7b918/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
+github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
+github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
 github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -587,8 +587,9 @@
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
 github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
 github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
@@ -660,8 +661,8 @@
 github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/polarismesh/polaris-go v1.0.0 h1:JIBANM5nfhu5knbg269kldQ58bSSV7a6AzTQk1OZwt8=
-github.com/polarismesh/polaris-go v1.0.0/go.mod h1:uzNFDShCN+UhBncwwNqNVhPpI1ZXYwPlb9N/aE+/vE0=
+github.com/polarismesh/polaris-go v1.0.1 h1:Zqr8ZtxsJQsxt0MGyC/fFsF861ogoJCz16yWFJ/t54Q=
+github.com/polarismesh/polaris-go v1.0.1/go.mod h1:3NOqn3QquPdEdY6YhPrsWGvBVCpKhPBGt0Hspq3yEqY=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
@@ -734,7 +735,6 @@
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@@ -853,7 +853,6 @@
 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4=
 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
 go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
@@ -950,7 +949,6 @@
 golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@@ -968,6 +966,7 @@
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211105192438-b53810dc28af h1:SMeNJG/vclJ5wyBBd4xupMsSJIHTd1coW9g7q6KOjmY=
 golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=