Skip to content

Commit 8d7c1c1

Browse files
authored
Merge pull request #122 from pantianying/master
generic#invoke (go to java)
2 parents 4379d39 + 0c6e36c commit 8d7c1c1

File tree

8 files changed

+291
-6
lines changed

8 files changed

+291
-6
lines changed

common/constant/default.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ const (
3838
PREFIX_DEFAULT_KEY = "default."
3939
DEFAULT_SERVICE_FILTERS = "echo"
4040
DEFAULT_REFERENCE_FILTERS = ""
41+
GENERIC_REFERENCE_FILTERS = "generic"
42+
GENERIC = "$invoke"
4143
ECHO = "$echo"
4244
)
4345

common/constant/key.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const (
3030
METHODS_KEY = "methods"
3131
TIMEOUT_KEY = "timeout"
3232
BEAN_NAME_KEY = "bean.name"
33+
GENERIC_KEY = "generic"
3334
)
3435

3536
const (

config/config_loader.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ func Load() {
6666
logger.Errorf("[consumer config center refresh] %#v", err)
6767
}
6868
for key, ref := range consumerConfig.References {
69+
if ref.Generic {
70+
genericService := NewGenericService(key)
71+
SetConsumerService(genericService)
72+
}
6973
rpcService := GetConsumerService(key)
7074

7175
if rpcService == nil {

config/generic_service.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package config
18+
19+
type GenericService struct {
20+
Invoke func(req []interface{}) (interface{}, error) `dubbo:"$invoke"`
21+
referenceStr string
22+
}
23+
24+
func NewGenericService(referenceStr string) *GenericService {
25+
return &GenericService{referenceStr: referenceStr}
26+
}
27+
28+
func (u *GenericService) Reference() string {
29+
return u.referenceStr
30+
}

config/reference_config.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type ReferenceConfig struct {
5555
Params map[string]string `yaml:"params" json:"params,omitempty" property:"params"`
5656
invoker protocol.Invoker
5757
urls []*common.URL
58+
Generic bool `yaml:"generic" json:"generic,omitempty" property:"generic"`
5859
}
5960

6061
func (c *ReferenceConfig) Prefix() string {
@@ -110,7 +111,6 @@ func (refconfig *ReferenceConfig) Refer() {
110111
regUrl.SubURL = url
111112
}
112113
}
113-
114114
if len(refconfig.urls) == 1 {
115115
refconfig.invoker = extension.GetProtocol(refconfig.urls[0].Protocol).Refer(*refconfig.urls[0])
116116
} else {
@@ -157,6 +157,7 @@ func (refconfig *ReferenceConfig) getUrlMap() url.Values {
157157
urlMap.Set(constant.RETRIES_KEY, strconv.FormatInt(refconfig.Retries, 10))
158158
urlMap.Set(constant.GROUP_KEY, refconfig.Group)
159159
urlMap.Set(constant.VERSION_KEY, refconfig.Version)
160+
urlMap.Set(constant.GENERIC_KEY, strconv.FormatBool(refconfig.Generic))
160161
//getty invoke async or sync
161162
urlMap.Set(constant.ASYNC_KEY, strconv.FormatBool(refconfig.async))
162163

@@ -170,7 +171,11 @@ func (refconfig *ReferenceConfig) getUrlMap() url.Values {
170171
urlMap.Set(constant.ENVIRONMENT_KEY, consumerConfig.ApplicationConfig.Environment)
171172

172173
//filter
173-
urlMap.Set(constant.REFERENCE_FILTER_KEY, mergeValue(consumerConfig.Filter, refconfig.Filter, constant.DEFAULT_REFERENCE_FILTERS))
174+
var defaultReferenceFilter = constant.DEFAULT_REFERENCE_FILTERS
175+
if refconfig.Generic {
176+
defaultReferenceFilter = constant.GENERIC_REFERENCE_FILTERS + defaultReferenceFilter
177+
}
178+
urlMap.Set(constant.REFERENCE_FILTER_KEY, mergeValue(consumerConfig.Filter, refconfig.Filter, defaultReferenceFilter))
174179

175180
for _, v := range refconfig.Methods {
176181
urlMap.Set("methods."+v.Name+"."+constant.LOADBALANCE_KEY, v.Loadbalance)
@@ -180,3 +185,11 @@ func (refconfig *ReferenceConfig) getUrlMap() url.Values {
180185
return urlMap
181186

182187
}
188+
func (refconfig *ReferenceConfig) GenericLoad(id string) {
189+
genericService := NewGenericService(refconfig.id)
190+
SetConsumerService(genericService)
191+
refconfig.id = id
192+
refconfig.Refer()
193+
refconfig.Implement(genericService)
194+
return
195+
}

examples/general/dubbo/go-client/app/client.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,15 @@ import (
2525
"syscall"
2626
"time"
2727
)
28-
2928
import (
30-
"github.com/apache/dubbo-go-hessian2"
29+
hessian "github.com/apache/dubbo-go-hessian2"
3130
)
3231

3332
import (
3433
"github.com/apache/dubbo-go/common/logger"
3534
_ "github.com/apache/dubbo-go/common/proxy/proxy_factory"
3635
"github.com/apache/dubbo-go/config"
37-
_ "github.com/apache/dubbo-go/protocol/dubbo"
36+
"github.com/apache/dubbo-go/protocol/dubbo"
3837
_ "github.com/apache/dubbo-go/registry/protocol"
3938

4039
_ "github.com/apache/dubbo-go/filter/impl"
@@ -65,7 +64,8 @@ func main() {
6564
test1()
6665
println("\n\ntest2")
6766
test2()
68-
67+
println("\n\ntest3")
68+
test3()
6969
initSignal()
7070
}
7171

@@ -288,3 +288,24 @@ func test2() {
288288
}
289289
println("error: %v", err)
290290
}
291+
func test3() {
292+
var appName = "UserProviderGer"
293+
var referenceConfig = config.ReferenceConfig{
294+
InterfaceName: "com.ikurento.user.UserProvider",
295+
Cluster: "failover",
296+
Registry: "hangzhouzk",
297+
Protocol: dubbo.DUBBO,
298+
Generic: true,
299+
}
300+
referenceConfig.GenericLoad(appName) //appName is the unique identification of RPCService
301+
302+
time.Sleep(3 * time.Second)
303+
println("\n\n\nstart to generic invoke")
304+
resp, err := referenceConfig.GetRPCService().(*config.GenericService).Invoke([]interface{}{"GetUser", []string{"java.lang.String"}, []interface{}{"A003"}})
305+
if err != nil {
306+
panic(err)
307+
}
308+
println("res: %v\n", resp)
309+
println("succ!")
310+
311+
}

filter/impl/generic_filter.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package impl
19+
20+
import (
21+
"reflect"
22+
"strings"
23+
)
24+
import (
25+
hessian "github.com/apache/dubbo-go-hessian2"
26+
)
27+
import (
28+
"github.com/apache/dubbo-go/common/constant"
29+
"github.com/apache/dubbo-go/common/extension"
30+
"github.com/apache/dubbo-go/filter"
31+
"github.com/apache/dubbo-go/protocol"
32+
invocation2 "github.com/apache/dubbo-go/protocol/invocation"
33+
)
34+
35+
const (
36+
GENERIC = "generic"
37+
)
38+
39+
func init() {
40+
extension.SetFilter(GENERIC, GetGenericFilter)
41+
}
42+
43+
// when do a generic invoke, struct need to be map
44+
45+
type GenericFilter struct{}
46+
47+
func (ef *GenericFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
48+
if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 {
49+
oldArguments := invocation.Arguments()
50+
var newParams []hessian.Object
51+
if oldParams, ok := oldArguments[2].([]interface{}); ok {
52+
for i := range oldParams {
53+
newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i])))
54+
}
55+
} else {
56+
return invoker.Invoke(invocation)
57+
}
58+
newArguments := []interface{}{
59+
oldArguments[0],
60+
oldArguments[1],
61+
newParams,
62+
}
63+
newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments())
64+
newInvocation.SetReply(invocation.Reply())
65+
return invoker.Invoke(newInvocation)
66+
}
67+
return invoker.Invoke(invocation)
68+
}
69+
70+
func (ef *GenericFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
71+
return result
72+
}
73+
74+
func GetGenericFilter() filter.Filter {
75+
return &GenericFilter{}
76+
}
77+
func struct2MapAll(obj interface{}) interface{} {
78+
if obj == nil {
79+
return obj
80+
}
81+
t := reflect.TypeOf(obj)
82+
v := reflect.ValueOf(obj)
83+
if t.Kind() == reflect.Struct {
84+
result := make(map[string]interface{}, t.NumField())
85+
for i := 0; i < t.NumField(); i++ {
86+
if v.Field(i).Kind() == reflect.Struct {
87+
if v.Field(i).CanInterface() {
88+
setInMap(result, t.Field(i), struct2MapAll(v.Field(i).Interface()))
89+
}
90+
} else if v.Field(i).Kind() == reflect.Slice {
91+
if v.Field(i).CanInterface() {
92+
setInMap(result, t.Field(i), struct2MapAll(v.Field(i).Interface()))
93+
}
94+
} else {
95+
if v.Field(i).CanInterface() {
96+
setInMap(result, t.Field(i), v.Field(i).Interface())
97+
}
98+
}
99+
}
100+
return result
101+
} else if t.Kind() == reflect.Slice {
102+
value := reflect.ValueOf(obj)
103+
var newTemps = make([]interface{}, 0, value.Len())
104+
for i := 0; i < value.Len(); i++ {
105+
newTemp := struct2MapAll(value.Index(i).Interface())
106+
newTemps = append(newTemps, newTemp)
107+
}
108+
return newTemps
109+
} else {
110+
return obj
111+
}
112+
}
113+
func setInMap(m map[string]interface{}, structField reflect.StructField, value interface{}) (result map[string]interface{}) {
114+
result = m
115+
if tagName := structField.Tag.Get("m"); tagName == "" {
116+
result[headerAtoa(structField.Name)] = value
117+
} else {
118+
result[tagName] = value
119+
}
120+
return
121+
}
122+
func headerAtoa(a string) (b string) {
123+
b = strings.ToLower(a[:1]) + a[1:]
124+
return
125+
}

filter/impl/generic_filter_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package impl
19+
20+
import (
21+
"reflect"
22+
"testing"
23+
)
24+
import (
25+
"github.com/stretchr/testify/assert"
26+
)
27+
28+
func Test_struct2MapAll(t *testing.T) {
29+
var testData struct {
30+
AaAa string `m:"aaAa"`
31+
BaBa string
32+
CaCa struct {
33+
AaAa string
34+
BaBa string `m:"baBa"`
35+
XxYy struct {
36+
xxXx string `m:"xxXx"`
37+
Xx string `m:"xx"`
38+
} `m:"xxYy"`
39+
} `m:"caCa"`
40+
}
41+
testData.AaAa = "1"
42+
testData.BaBa = "1"
43+
testData.CaCa.BaBa = "2"
44+
testData.CaCa.AaAa = "2"
45+
testData.CaCa.XxYy.xxXx = "3"
46+
testData.CaCa.XxYy.Xx = "3"
47+
m := struct2MapAll(testData).(map[string]interface{})
48+
assert.Equal(t, "1", m["aaAa"].(string))
49+
assert.Equal(t, "1", m["baBa"].(string))
50+
assert.Equal(t, "2", m["caCa"].(map[string]interface{})["aaAa"].(string))
51+
assert.Equal(t, "3", m["caCa"].(map[string]interface{})["xxYy"].(map[string]interface{})["xx"].(string))
52+
53+
assert.Equal(t, reflect.Map, reflect.TypeOf(m["caCa"]).Kind())
54+
assert.Equal(t, reflect.Map, reflect.TypeOf(m["caCa"].(map[string]interface{})["xxYy"]).Kind())
55+
}
56+
57+
type testStruct struct {
58+
AaAa string
59+
BaBa string `m:"baBa"`
60+
XxYy struct {
61+
xxXx string `m:"xxXx"`
62+
Xx string `m:"xx"`
63+
} `m:"xxYy"`
64+
}
65+
66+
func Test_struct2MapAll_Slice(t *testing.T) {
67+
var testData struct {
68+
AaAa string `m:"aaAa"`
69+
BaBa string
70+
CaCa []testStruct `m:"caCa"`
71+
}
72+
testData.AaAa = "1"
73+
testData.BaBa = "1"
74+
var tmp testStruct
75+
tmp.BaBa = "2"
76+
tmp.AaAa = "2"
77+
tmp.XxYy.xxXx = "3"
78+
tmp.XxYy.Xx = "3"
79+
testData.CaCa = append(testData.CaCa, tmp)
80+
m := struct2MapAll(testData).(map[string]interface{})
81+
82+
assert.Equal(t, "1", m["aaAa"].(string))
83+
assert.Equal(t, "1", m["baBa"].(string))
84+
assert.Equal(t, "2", m["caCa"].([]interface{})[0].(map[string]interface{})["aaAa"].(string))
85+
assert.Equal(t, "3", m["caCa"].([]interface{})[0].(map[string]interface{})["xxYy"].(map[string]interface{})["xx"].(string))
86+
87+
assert.Equal(t, reflect.Slice, reflect.TypeOf(m["caCa"]).Kind())
88+
assert.Equal(t, reflect.Map, reflect.TypeOf(m["caCa"].([]interface{})[0].(map[string]interface{})["xxYy"]).Kind())
89+
}

0 commit comments

Comments
 (0)