dubbo.apache.org/dubbo-go/v3@v3.1.1/filter/generic/service_filter.go (about) 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 generic 19 20 import ( 21 "context" 22 "sync" 23 ) 24 25 import ( 26 hessian "github.com/apache/dubbo-go-hessian2" 27 28 "github.com/dubbogo/gost/log/logger" 29 30 perrors "github.com/pkg/errors" 31 ) 32 33 import ( 34 "dubbo.apache.org/dubbo-go/v3/common" 35 "dubbo.apache.org/dubbo-go/v3/common/constant" 36 "dubbo.apache.org/dubbo-go/v3/common/extension" 37 "dubbo.apache.org/dubbo-go/v3/filter" 38 "dubbo.apache.org/dubbo-go/v3/protocol" 39 invocation2 "dubbo.apache.org/dubbo-go/v3/protocol/invocation" 40 ) 41 42 var ( 43 serviceGenericOnce sync.Once 44 serviceGeneric *genericServiceFilter 45 ) 46 47 func init() { 48 extension.SetFilter(constant.GenericServiceFilterKey, newGenericServiceFilter) 49 } 50 51 // genericServiceFilter is for Server 52 type genericServiceFilter struct{} 53 54 func newGenericServiceFilter() filter.Filter { 55 if serviceGeneric == nil { 56 serviceGenericOnce.Do(func() { 57 serviceGeneric = &genericServiceFilter{} 58 }) 59 } 60 return serviceGeneric 61 } 62 func (f *genericServiceFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { 63 if !invocation.IsGenericInvocation() { 64 return invoker.Invoke(ctx, invocation) 65 } 66 67 // get real invocation info from the generic invocation 68 mtdname := invocation.Arguments()[0].(string) 69 // types are not required in dubbo-go, for dubbo-go client to dubbo-go server, types could be nil 70 types := invocation.Arguments()[1] 71 args := invocation.Arguments()[2].([]hessian.Object) 72 73 logger.Debugf(`received a generic invocation: 74 MethodName: %s, 75 Types: %s, 76 Args: %s 77 `, mtdname, types, args) 78 79 // get the type of the argument 80 ivkUrl := invoker.GetURL() 81 svc := common.ServiceMap.GetServiceByServiceKey(ivkUrl.Protocol, ivkUrl.ServiceKey()) 82 method := svc.Method()[mtdname] 83 if method == nil { 84 return &protocol.RPCResult{ 85 Err: perrors.Errorf("\"%s\" method is not found, service key: %s", mtdname, ivkUrl.ServiceKey()), 86 } 87 } 88 argsType := method.ArgsType() 89 90 // get generic info from attachments of invocation, the default value is "true" 91 generic := invocation.GetAttachmentWithDefaultValue(constant.GenericKey, constant.GenericSerializationDefault) 92 // get generalizer according to value in the `generic` 93 g := getGeneralizer(generic) 94 95 if len(args) != len(argsType) { 96 return &protocol.RPCResult{ 97 Err: perrors.Errorf("the number of args(=%d) is not matched with \"%s\" method", len(args), mtdname), 98 } 99 } 100 101 // realize 102 newargs := make([]interface{}, len(argsType)) 103 for i := 0; i < len(argsType); i++ { 104 newarg, err := g.Realize(args[i], argsType[i]) 105 if err != nil { 106 return &protocol.RPCResult{ 107 Err: perrors.Errorf("realization failed, %v", err), 108 } 109 } 110 newargs[i] = newarg 111 } 112 113 // build a normal invocation 114 newivc := invocation2.NewRPCInvocation(mtdname, newargs, invocation.Attachments()) 115 newivc.SetReply(invocation.Reply()) 116 117 return invoker.Invoke(ctx, newivc) 118 } 119 120 func (f *genericServiceFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker, invocation protocol.Invocation) protocol.Result { 121 if invocation.IsGenericInvocation() && result.Result() != nil { 122 // get generic info from attachments of invocation, the default value is "true" 123 generic := invocation.GetAttachmentWithDefaultValue(constant.GenericKey, constant.GenericSerializationDefault) 124 // get generalizer according to value in the `generic` 125 g := getGeneralizer(generic) 126 127 obj, err := g.Generalize(result.Result()) 128 if err != nil { 129 err = perrors.Errorf("generalizaion failed, %v", err) 130 result.SetError(err) 131 result.SetResult(nil) 132 return result 133 } 134 result.SetResult(obj) 135 } 136 return result 137 }