Skip to content
Snippets Groups Projects
Commit 043719b1 authored by Patrick's avatar Patrick
Browse files

generic service filter

parent 155bcad7
No related branches found
No related tags found
No related merge requests found
......@@ -46,7 +46,7 @@ const (
const (
DEFAULT_KEY = "default"
PREFIX_DEFAULT_KEY = "default."
DEFAULT_SERVICE_FILTERS = "echo,token,accesslog,tps,execute,pshutdown"
DEFAULT_SERVICE_FILTERS = "echo,token,accesslog,tps,generic-service,execute,pshutdown"
DEFAULT_REFERENCE_FILTERS = "cshutdown"
GENERIC_REFERENCE_FILTERS = "generic"
GENERIC = "$invoke"
......
package impl
import (
hessian "github.com/apache/dubbo-go-hessian2"
"github.com/apache/dubbo-go/common"
"github.com/apache/dubbo-go/common/constant"
"github.com/apache/dubbo-go/common/extension"
"github.com/apache/dubbo-go/common/logger"
"github.com/apache/dubbo-go/filter"
"github.com/apache/dubbo-go/protocol"
invocation2 "github.com/apache/dubbo-go/protocol/invocation"
"github.com/mitchellh/mapstructure"
"reflect"
"strings"
)
const (
GENERIC_SERVICE = "generic-service"
GENERIC_SERIALIZATION_DEFAULT = "true"
)
func init() {
extension.SetFilter(GENERIC_SERVICE, GetGenericServiceFilter)
}
type GenericServiceFilter struct{}
func (ef *GenericServiceFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
logger.Infof("invoking generic service filter.")
logger.Debugf("generic service filter methodName:%v,args:%v", invocation.MethodName(), len(invocation.Arguments()))
if invocation.MethodName() != constant.GENERIC || len(invocation.Arguments()) != 3 {
return invoker.Invoke(invocation)
}
var (
err error
methodName string
newParams []interface{}
genericKey string
argsType []reflect.Type
oldParams []hessian.Object
)
url := invoker.GetUrl()
methodName = invocation.Arguments()[0].(string)
// get service
svc := common.ServiceMap.GetService(url.Protocol, strings.TrimPrefix(url.Path, "/"))
// get method
method := svc.Method()[methodName]
if method == nil {
logger.Errorf("[Generic Service Filter] Don't have this method: %v", method)
return &protocol.RPCResult{}
}
argsType = method.ArgsType()
genericKey = invocation.AttachmentsByKey(constant.GENERIC_KEY, GENERIC_SERIALIZATION_DEFAULT)
if genericKey == GENERIC_SERIALIZATION_DEFAULT {
oldParams = invocation.Arguments()[2].([]hessian.Object)
} else {
logger.Errorf("[Generic Service Filter] Don't support this generic: %v", genericKey)
return &protocol.RPCResult{}
}
if len(oldParams) != len(argsType) {
logger.Errorf("[Generic Service Filter] method:%s invocation arguments number was wrong", methodName)
return &protocol.RPCResult{}
}
// oldParams convert to newParams
for i := range argsType {
var newParam interface{}
if argsType[i].Kind() == reflect.Ptr {
newParam = reflect.New(argsType[i].Elem()).Interface()
err = mapstructure.Decode(oldParams[i], newParam)
} else if argsType[i].Kind() == reflect.Struct || argsType[i].Kind() == reflect.Slice {
newParam = reflect.New(argsType[i]).Interface()
err = mapstructure.Decode(oldParams[i], newParam)
newParam = reflect.ValueOf(newParam).Elem().Interface()
} else {
newParam = oldParams[i]
}
if err != nil {
logger.Errorf("[Generic Service Filter] decode arguments map to struct wrong")
}
newParams = append(newParams, newParam)
}
newInvocation := invocation2.NewRPCInvocation(methodName, newParams, invocation.Attachments())
newInvocation.SetReply(invocation.Reply())
return invoker.Invoke(newInvocation)
}
func (ef *GenericServiceFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 && result.Result() != nil {
s := reflect.ValueOf(result.Result()).Elem().Interface()
r := struct2MapAll(s)
result.SetResult(r)
}
return result
}
func GetGenericServiceFilter() filter.Filter {
return &GenericServiceFilter{}
}
package impl
import (
"context"
"errors"
hessian "github.com/apache/dubbo-go-hessian2"
"github.com/apache/dubbo-go/common"
"github.com/apache/dubbo-go/common/proxy/proxy_factory"
"github.com/apache/dubbo-go/protocol"
"github.com/apache/dubbo-go/protocol/invocation"
"github.com/stretchr/testify/assert"
"reflect"
"testing"
)
type TestStruct struct {
AaAa string
BaBa string `m:"baBa"`
XxYy struct {
xxXx string `m:"xxXx"`
Xx string `m:"xx"`
} `m:"xxYy"`
}
func (c *TestStruct) JavaClassName() string {
return "com.test.testStruct"
}
type TestService struct {
}
func (ts *TestService) MethodOne(ctx context.Context, test1 *TestStruct, test2 []TestStruct,
test3 interface{}, test4 []interface{}, test5 *string) (*TestStruct, error) {
if test1 == nil {
return nil, errors.New("param test1 is nil")
}
if test2 == nil {
return nil, errors.New("param test2 is nil")
}
if test3 == nil {
return nil, errors.New("param test3 is nil")
}
if test4 == nil {
return nil, errors.New("param test4 is nil")
}
if test5 == nil {
return nil, errors.New("param test5 is nil")
}
return &TestStruct{}, nil
}
func (s *TestService) Reference() string {
return "com.test.Path"
}
func TestGenericServiceFilter_Invoke(t *testing.T) {
hessian.RegisterPOJO(&TestStruct{})
methodName := "$invoke"
m := make(map[string]interface{})
m["AaAa"] = "nihao"
x := make(map[string]interface{})
x["xxXX"] = "nihaoxxx"
m["XxYy"] = x
aurguments := []interface{}{
"MethodOne",
nil,
[]hessian.Object{
hessian.Object(m),
hessian.Object(append(make([]map[string]interface{}, 1), m)),
hessian.Object("111"),
hessian.Object(append(make([]map[string]interface{}, 1), m)),
hessian.Object("222")},
}
s := &TestService{}
_, _ = common.ServiceMap.Register("testprotocol", s)
rpcInvocation := invocation.NewRPCInvocation(methodName, aurguments, nil)
filter := GetGenericServiceFilter()
url, _ := common.NewURL(context.Background(), "testprotocol://127.0.0.1:20000/com.test.Path")
result := filter.Invoke(&proxy_factory.ProxyInvoker{BaseInvoker: *protocol.NewBaseInvoker(url)}, rpcInvocation)
assert.NotNil(t, result)
assert.Nil(t, result.Error())
}
func TestGenericServiceFilter_Response(t *testing.T) {
ts := &TestStruct{
AaAa: "aaa",
BaBa: "bbb",
XxYy: struct {
xxXx string `m:"xxXx"`
Xx string `m:"xx"`
}{},
}
result := &protocol.RPCResult{
Rest: ts,
}
aurguments := []interface{}{
"MethodOne",
nil,
[]hessian.Object{nil},
}
filter := GetGenericServiceFilter()
methodName := "$invoke"
rpcInvocation := invocation.NewRPCInvocation(methodName, aurguments, nil)
r := filter.OnResponse(result, nil, rpcInvocation)
assert.NotNil(t, r.Result())
assert.Equal(t, reflect.ValueOf(r.Result()).Kind(), reflect.Map)
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment