|
18 | 18 |
|
19 | 19 | import org.apache.dubbo.common.URL; |
20 | 20 | import org.apache.dubbo.common.constants.CommonConstants; |
| 21 | +import org.apache.dubbo.common.stream.StreamObserver; |
21 | 22 | import org.apache.dubbo.common.utils.CollectionUtils; |
22 | 23 | import org.apache.dubbo.remoting.http12.exception.UnimplementedException; |
23 | 24 | import org.apache.dubbo.rpc.Invoker; |
|
30 | 31 |
|
31 | 32 | import java.io.IOException; |
32 | 33 | import java.io.InputStream; |
| 34 | +import java.lang.reflect.Type; |
33 | 35 | import java.util.Arrays; |
34 | 36 | import java.util.List; |
35 | 37 |
|
@@ -86,62 +88,151 @@ public static MethodDescriptor findMethodDescriptor( |
86 | 88 |
|
87 | 89 | public static MethodDescriptor findReflectionMethodDescriptor( |
88 | 90 | ServiceDescriptor serviceDescriptor, String methodName) { |
89 | | - MethodDescriptor methodDescriptor = null; |
| 91 | + MethodDescriptor methodDescriptor = findWellKnownMethodDescriptor(methodName); |
| 92 | + if (methodDescriptor != null) { |
| 93 | + return methodDescriptor; |
| 94 | + } |
| 95 | + |
| 96 | + List<MethodDescriptor> methodDescriptors = serviceDescriptor.getMethods(methodName); |
| 97 | + methodDescriptor = findSingleOrGeneratedUnaryMethodDescriptor(methodDescriptors); |
| 98 | + if (methodDescriptor == null && CollectionUtils.isNotEmpty(methodDescriptors)) { |
| 99 | + throw new UnimplementedException("method:" + methodName); |
| 100 | + } |
| 101 | + return methodDescriptor; |
| 102 | + } |
| 103 | + |
| 104 | + public static MethodDescriptor findTripleMethodDescriptor( |
| 105 | + ServiceDescriptor serviceDescriptor, String methodName, InputStream rawMessage) throws IOException { |
| 106 | + MethodDescriptor methodDescriptor = findWellKnownMethodDescriptor(methodName); |
| 107 | + if (methodDescriptor != null) { |
| 108 | + return methodDescriptor; |
| 109 | + } |
| 110 | + |
| 111 | + List<MethodDescriptor> methodDescriptors = serviceDescriptor.getMethods(methodName); |
| 112 | + if (CollectionUtils.isEmpty(methodDescriptors)) { |
| 113 | + throw new UnimplementedException("method:" + methodName); |
| 114 | + } |
| 115 | + if (methodDescriptors.size() == 1) { |
| 116 | + return methodDescriptors.get(0); |
| 117 | + } |
| 118 | + |
| 119 | + TripleRequestWrapper request = parseRequestWrapper(rawMessage); |
| 120 | + List<String> argTypes = request == null ? null : request.getArgTypes(); |
| 121 | + if (argTypes != null) { |
| 122 | + MethodDescriptor matchedDescriptor = |
| 123 | + findMethodDescriptorByParamTypes(methodDescriptors, argTypes.toArray(new String[0])); |
| 124 | + if (matchedDescriptor != null) { |
| 125 | + return matchedDescriptor; |
| 126 | + } |
| 127 | + if (CollectionUtils.isNotEmpty(argTypes)) { |
| 128 | + throw new UnimplementedException("method:" + methodName); |
| 129 | + } |
| 130 | + } |
| 131 | + |
| 132 | + MethodDescriptor generatedUnaryDescriptor = findGeneratedUnaryMethodDescriptor(methodDescriptors); |
| 133 | + if (generatedUnaryDescriptor != null) { |
| 134 | + return generatedUnaryDescriptor; |
| 135 | + } |
| 136 | + throw new UnimplementedException("method:" + methodName); |
| 137 | + } |
| 138 | + |
| 139 | + private static MethodDescriptor findSingleOrGeneratedUnaryMethodDescriptor( |
| 140 | + List<MethodDescriptor> methodDescriptors) { |
| 141 | + if (CollectionUtils.isEmpty(methodDescriptors)) { |
| 142 | + return null; |
| 143 | + } |
| 144 | + // In most cases there is only one method |
| 145 | + if (methodDescriptors.size() == 1) { |
| 146 | + return methodDescriptors.get(0); |
| 147 | + } |
| 148 | + return findGeneratedUnaryMethodDescriptor(methodDescriptors); |
| 149 | + } |
| 150 | + |
| 151 | + private static TripleRequestWrapper parseRequestWrapper(InputStream rawMessage) throws IOException { |
| 152 | + rawMessage.mark(Integer.MAX_VALUE); |
| 153 | + try { |
| 154 | + return TripleRequestWrapper.parseFrom(rawMessage); |
| 155 | + } finally { |
| 156 | + rawMessage.reset(); |
| 157 | + } |
| 158 | + } |
| 159 | + |
| 160 | + private static MethodDescriptor findWellKnownMethodDescriptor(String methodName) { |
90 | 161 | if (isGeneric(methodName)) { |
91 | | - // There should be one and only one |
92 | | - methodDescriptor = ServiceDescriptorInternalCache.genericService() |
| 162 | + return ServiceDescriptorInternalCache.genericService() |
93 | 163 | .getMethods(methodName) |
94 | 164 | .get(0); |
95 | | - } else if (isEcho(methodName)) { |
96 | | - // There should be one and only one |
| 165 | + } |
| 166 | + if (isEcho(methodName)) { |
97 | 167 | return ServiceDescriptorInternalCache.echoService() |
98 | 168 | .getMethods(methodName) |
99 | 169 | .get(0); |
100 | | - } else { |
101 | | - List<MethodDescriptor> methodDescriptors = serviceDescriptor.getMethods(methodName); |
102 | | - if (CollectionUtils.isEmpty(methodDescriptors)) { |
103 | | - return null; |
104 | | - } |
105 | | - // In most cases there is only one method |
106 | | - if (methodDescriptors.size() == 1) { |
107 | | - methodDescriptor = methodDescriptors.get(0); |
108 | | - } |
109 | | - // generated unary method ,use unary type |
110 | | - // Response foo(Request) |
111 | | - // void foo(Request,StreamObserver<Response>) |
112 | | - if (methodDescriptors.size() == 2) { |
113 | | - if (methodDescriptors.get(1).getRpcType() == MethodDescriptor.RpcType.SERVER_STREAM) { |
114 | | - methodDescriptor = methodDescriptors.get(0); |
115 | | - } else if (methodDescriptors.get(0).getRpcType() == MethodDescriptor.RpcType.SERVER_STREAM) { |
116 | | - methodDescriptor = methodDescriptors.get(1); |
117 | | - } |
118 | | - } |
119 | 170 | } |
120 | | - return methodDescriptor; |
| 171 | + return null; |
121 | 172 | } |
122 | 173 |
|
123 | | - public static MethodDescriptor findTripleMethodDescriptor( |
124 | | - ServiceDescriptor serviceDescriptor, String methodName, InputStream rawMessage) throws IOException { |
125 | | - MethodDescriptor methodDescriptor = findReflectionMethodDescriptor(serviceDescriptor, methodName); |
126 | | - if (methodDescriptor == null) { |
127 | | - rawMessage.mark(Integer.MAX_VALUE); |
128 | | - List<MethodDescriptor> methodDescriptors = serviceDescriptor.getMethods(methodName); |
129 | | - TripleRequestWrapper request = TripleRequestWrapper.parseFrom(rawMessage); |
130 | | - String[] paramTypes = request.getArgTypes().toArray(new String[0]); |
| 174 | + private static MethodDescriptor findMethodDescriptorByParamTypes( |
| 175 | + List<MethodDescriptor> methodDescriptors, String[] paramTypes) { |
| 176 | + for (MethodDescriptor descriptor : methodDescriptors) { |
131 | 177 | // wrapper mode the method can overload so maybe list |
132 | | - for (MethodDescriptor descriptor : methodDescriptors) { |
133 | | - // params type is array |
134 | | - if (Arrays.equals(descriptor.getCompatibleParamSignatures(), paramTypes)) { |
135 | | - methodDescriptor = descriptor; |
136 | | - break; |
137 | | - } |
| 178 | + if (Arrays.equals(descriptor.getCompatibleParamSignatures(), paramTypes)) { |
| 179 | + return descriptor; |
138 | 180 | } |
139 | | - if (methodDescriptor == null) { |
140 | | - throw new UnimplementedException("method:" + methodName); |
| 181 | + } |
| 182 | + return null; |
| 183 | + } |
| 184 | + |
| 185 | + private static MethodDescriptor findGeneratedUnaryMethodDescriptor(List<MethodDescriptor> methodDescriptors) { |
| 186 | + // Generated unary methods may expose two Java methods for the same RPC: |
| 187 | + // Response foo(Request) |
| 188 | + // void foo(Request, StreamObserver<Response>) |
| 189 | + if (methodDescriptors.size() != 2) { |
| 190 | + return null; |
| 191 | + } |
| 192 | + |
| 193 | + MethodDescriptor unaryMethodDescriptor = null; |
| 194 | + MethodDescriptor serverStreamMethodDescriptor = null; |
| 195 | + for (MethodDescriptor descriptor : methodDescriptors) { |
| 196 | + if (descriptor.getRpcType() == MethodDescriptor.RpcType.UNARY) { |
| 197 | + unaryMethodDescriptor = descriptor; |
| 198 | + } else if (descriptor.getRpcType() == MethodDescriptor.RpcType.SERVER_STREAM) { |
| 199 | + serverStreamMethodDescriptor = descriptor; |
141 | 200 | } |
142 | | - rawMessage.reset(); |
143 | 201 | } |
144 | | - return methodDescriptor; |
| 202 | + if (unaryMethodDescriptor == null || serverStreamMethodDescriptor == null) { |
| 203 | + return null; |
| 204 | + } |
| 205 | + if (!Arrays.equals( |
| 206 | + unaryMethodDescriptor.getParameterClasses(), |
| 207 | + getServerStreamRequestTypes(serverStreamMethodDescriptor))) { |
| 208 | + return null; |
| 209 | + } |
| 210 | + if (!isSameResponseType(unaryMethodDescriptor, serverStreamMethodDescriptor)) { |
| 211 | + return null; |
| 212 | + } |
| 213 | + return unaryMethodDescriptor; |
| 214 | + } |
| 215 | + |
| 216 | + private static Class<?>[] getServerStreamRequestTypes(MethodDescriptor serverStreamMethodDescriptor) { |
| 217 | + Class<?>[] parameterClasses = serverStreamMethodDescriptor.getParameterClasses(); |
| 218 | + if (parameterClasses.length == 0 |
| 219 | + || !StreamObserver.class.isAssignableFrom(parameterClasses[parameterClasses.length - 1])) { |
| 220 | + return null; |
| 221 | + } |
| 222 | + return Arrays.copyOf(parameterClasses, parameterClasses.length - 1); |
| 223 | + } |
| 224 | + |
| 225 | + private static boolean isSameResponseType( |
| 226 | + MethodDescriptor unaryMethodDescriptor, MethodDescriptor serverStreamMethodDescriptor) { |
| 227 | + Type[] returnTypes = unaryMethodDescriptor.getReturnTypes(); |
| 228 | + if (returnTypes.length == 0 || !(returnTypes[0] instanceof Class)) { |
| 229 | + return false; |
| 230 | + } |
| 231 | + Class<?> actualResponseType = serverStreamMethodDescriptor.getActualResponseType(); |
| 232 | + if (actualResponseType == null) { |
| 233 | + return false; |
| 234 | + } |
| 235 | + return returnTypes[0].equals(actualResponseType); |
145 | 236 | } |
146 | 237 |
|
147 | 238 | private static boolean isGeneric(String methodName) { |
|
0 commit comments