From 205273ca8cd8d04483e7161c9561710c6dc1e03a Mon Sep 17 00:00:00 2001
From: Sean Yang
Date: Tue, 19 Dec 2023 02:04:19 +0800
Subject: [PATCH] v2
---
.editorconfig | 38 +-
.../apache/dubbo/common/io/StreamUtils.java | 52 ++
.../dubbo/common/utils/CollectionUtils.java | 49 +-
.../apache/dubbo/common/utils/LRU2Cache.java | 48 +-
.../apache/dubbo/common/utils/LRUCache.java | 75 ++-
.../dubbo/common/utils/StringUtils.java | 69 +++
.../apache/dubbo/common/utils/TimeUtils.java | 25 +
.../dubbo/reactive/CreateObserverAdapter.java | 63 --
.../reactive/ManyToManyMethodHandlerTest.java | 48 --
.../reactive/ManyToOneMethodHandlerTest.java | 70 ---
.../reactive/OneToManyMethodHandlerTest.java | 71 ---
.../AbstractServerHttpChannelObserver.java | 42 +-
.../dubbo/remoting/http12/HttpChannel.java | 2 +
.../dubbo/remoting/http12/HttpCookie.java | 123 ++++
.../dubbo/remoting/http12/HttpMethods.java | 60 ++
.../dubbo/remoting/http12/HttpRequest.java | 134 +++++
.../dubbo/remoting/http12/HttpResponse.java | 85 +++
.../dubbo/remoting/http12/HttpResult.java | 29 +
.../dubbo/remoting/http12/HttpUtils.java | 195 +++++++
.../http12/exception/DecodeException.java | 4 +
.../http12/exception/HttpStatusException.java | 5 +
.../http12/h2/Http2ChannelDelegate.java | 5 +
.../DefaultHttpMessageAdapterFactory.java | 37 ++
.../http12/message/DefaultHttpRequest.java | 539 ++++++++++++++++++
.../http12/message/DefaultHttpResponse.java | 270 +++++++++
.../http12/message/DefaultHttpResult.java | 56 ++
.../message/HttpMessageAdapterFactory.java | 35 ++
.../http12/message/HttpMessageDecoder.java | 5 +-
.../http12/message/HttpMessageEncoder.java | 3 +-
.../http12/message/codec/CodecUtils.java | 121 ++--
.../http12/message/codec/JsonCodec.java | 18 +-
.../http12/message/codec/JsonPbCodec.java | 15 +-
.../message/codec/MultipartDecoder.java | 2 +-
.../http12/message/codec/PlainTextCodec.java | 22 +-
.../message/codec/UrlEncodeFormCodec.java | 12 +-
.../http12/message/codec/XmlCodec.java | 6 +-
.../http12/netty4/h1/NettyHttp1Channel.java | 5 +
.../h1/NettyHttp1ConnectionHandler.java | 76 +--
.../netty4/h2/NettyH2StreamChannel.java | 5 +
.../h2/NettyHttp2ProtocolSelectorHandler.java | 16 +-
.../http12/message/codec/CodeUtilsTest.java | 13 +-
dubbo-rpc/dubbo-rpc-triple/pom.xml | 22 +
.../rpc/protocol/tri/DescriptorUtils.java | 155 +++++
.../rpc/protocol/tri/RequestMetadata.java | 4 +-
.../rpc/protocol/tri/TripleConstant.java | 19 +-
.../rpc/protocol/tri/TripleHeaderEnum.java | 1 +
.../rpc/protocol/tri/TripleHttp2Protocol.java | 12 -
.../dubbo/rpc/protocol/tri/TripleInvoker.java | 2 +-
.../rpc/protocol/tri/TripleProtocol.java | 24 +-
...ripleReflectionTypeDescriberRegistrar.java | 3 +-
.../protocol/tri/call/AbstractServerCall.java | 438 --------------
.../tri/call/AbstractServerCallListener.java | 102 ----
.../tri/call/BiStreamServerCallListener.java | 61 --
.../call/ReflectionAbstractServerCall.java | 214 -------
.../rpc/protocol/tri/call/ServerCall.java | 75 ---
.../call/ServerStreamServerCallListener.java | 51 --
.../tri/call/StubAbstractServerCall.java | 66 ---
.../tri/call/UnaryServerCallListener.java | 84 ---
.../tri/h12/AbstractServerCallListener.java | 4 +-
.../h12/AbstractServerTransportListener.java | 382 +++----------
.../protocol/tri/h12/HttpHandlerMapping.java | 105 ++++
.../tri/h12/TripleProtocolDetector.java | 34 +-
.../tri/h12/grpc/GrpcCompositeCodec.java | 5 +-
.../h12/grpc/GrpcCompositeCodecFactory.java | 7 +-
.../tri/h12/grpc/GrpcHandlerMapping.java | 53 ++
.../GrpcHttp2ServerTransportListener.java | 156 ++---
.../rpc/protocol/tri/h12/grpc/GrpcUtils.java | 51 --
.../h12/grpc/ProtobufHttpMessageCodec.java | 5 +-
.../DefaultHttp11ServerTransportListener.java | 69 +--
.../GenericHttp2ServerTransportListener.java | 154 ++---
.../h12/http2/Http2ServerStreamObserver.java | 2 +-
.../observer/ServerCallToObserverAdapter.java | 136 -----
.../protocol/tri/rest/ArgumentConverter.java | 24 +
.../protocol/tri/rest/ArgumentResolver.java | 28 +
.../tri/rest/RestHttpMessageCodec.java | 85 +++
.../protocol/tri/rest/RestInvokeFilter.java | 41 ++
.../DefaultRequestMappingRegistry.java | 100 ++++
.../tri/rest/mapping/MethodWalker.java | 26 +
.../protocol/tri/rest/mapping/RadixTree.java | 28 +
.../tri/rest/mapping/RequestMapping.java | 45 ++
.../rest/mapping/RequestMappingRegistry.java | 35 ++
.../mapping/condition/AbstractCondition.java | 22 +
.../tri/rest/mapping/condition/Condition.java | 28 +
.../mapping/condition/ConsumesCondition.java | 19 +
.../mapping/condition/HeadersCondition.java | 19 +
.../mapping/condition/MethodsCondition.java | 19 +
.../mapping/condition/ParamsCondition.java | 19 +
.../mapping/condition/PathsCondition.java | 19 +
.../mapping/condition/ProducesCondition.java | 19 +
.../tri/rest/meta/MappingDescriptor.java | 71 +++
.../tri/rest/meta/ParameterDescriptor.java | 51 ++
.../tri/rest/support/resteasy/.gitkeeper | 0
.../tri/rest/support/servlet/.gitkeeper | 0
.../ServletHttpMessageAdapterFactory.java | 38 ++
.../servlet/ServletHttpRequestAdaptee.java | 385 +++++++++++++
.../servlet/ServletHttpResponseAdaptee.java | 137 +++++
.../tri/rest/support/spring/.gitkeeper | 0
.../tri/route/DefaultRequestRouter.java | 68 +++
.../rpc/protocol/tri/route/HandlerInfo.java | 126 ++++
.../protocol/tri/route/HandlerMapping.java | 31 +
.../rpc/protocol/tri/route/RequestRouter.java | 30 +
.../tri/route/RpcInvocationBuildContext.java | 51 ++
.../tri/service/TriBuiltinService.java | 4 +-
.../rpc/protocol/tri/stream/ServerStream.java | 64 ---
.../rpc/protocol/tri/stream/StreamUtils.java | 249 ++++----
.../tri/stream/TripleServerStream.java | 505 ----------------
.../AbstractH2TransportListener.java | 2 +-
.../TripleHttp2FrameServerHandler.java | 115 ----
.../tri/call/ReflectionServerCallTest.java | 92 ---
.../protocol/tri/call/StubServerCallTest.java | 68 ---
.../protocol/tri/stream/StreamUtilsTest.java | 6 +-
111 files changed, 4319 insertions(+), 3394 deletions(-)
delete mode 100644 dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/CreateObserverAdapter.java
delete mode 100644 dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToManyMethodHandlerTest.java
delete mode 100644 dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToOneMethodHandlerTest.java
delete mode 100644 dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/OneToManyMethodHandlerTest.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpCookie.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpRequest.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResponse.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResult.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpMessageAdapterFactory.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResponse.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java
create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageAdapterFactory.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/DescriptorUtils.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCall.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCallListener.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/BiStreamServerCallListener.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ReflectionAbstractServerCall.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ServerCall.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ServerStreamServerCallListener.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/StubAbstractServerCall.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/UnaryServerCallListener.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpHandlerMapping.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHandlerMapping.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcUtils.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/observer/ServerCallToObserverAdapter.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/ArgumentConverter.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/ArgumentResolver.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestHttpMessageCodec.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestInvokeFilter.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/MethodWalker.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/AbstractCondition.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/Condition.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/HeadersCondition.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ParamsCondition.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathsCondition.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/meta/MappingDescriptor.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/meta/ParameterDescriptor.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/resteasy/.gitkeeper
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/.gitkeeper
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpMessageAdapterFactory.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpRequestAdaptee.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpResponseAdaptee.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/.gitkeeper
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/DefaultRequestRouter.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/HandlerInfo.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/HandlerMapping.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/RequestRouter.java
create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/RpcInvocationBuildContext.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/ServerStream.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleServerStream.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/TripleHttp2FrameServerHandler.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/call/ReflectionServerCallTest.java
delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/call/StubServerCallTest.java
diff --git a/.editorconfig b/.editorconfig
index 68a55e785793..f1ceb18698e3 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -23,12 +23,44 @@ root = true
[*]
charset = utf-8
end_of_line = lf
+indent_size = 4
+indent_style = space
+tab_width = 4
+max_line_length = 360
insert_final_newline = true
+trim_trailing_whitespace = true
# 4 space indentation
-[*.{java,xml}]
-indent_style = space
-indent_size = 4
+[*.java]
+ij_java_continuation_indent_size = 8
+ij_java_align_multiline_deconstruction_list_components = false
+ij_java_align_multiline_parameters = false
+ij_java_call_parameters_new_line_after_left_paren = true
+ij_java_call_parameters_wrap = normal
+ij_java_keep_control_statement_in_one_line = false
+ij_java_keep_first_column_comment = false
+ij_java_keep_line_breaks = false
+ij_java_method_call_chain_wrap = normal
+ij_java_method_parameters_new_line_after_left_paren = true
+ij_java_rparen_on_new_line_in_deconstruction_pattern = false
+ij_java_wrap_first_method_in_call_chain = true
+ij_java_wrap_long_lines = true
+ij_java_class_count_to_use_import_on_demand = 999
+ij_java_names_count_to_use_import_on_demand = 999
+ij_java_insert_inner_class_imports = true
+ij_java_for_brace_force = always
+ij_java_if_brace_force = always
+ij_java_blank_lines_around_class = 1
+
+[*.json]
+tab_width = 2
+
+[*.{yml,yaml}]
+indent_size = 2
+
+[*.xml]
+ij_xml_attribute_wrap = off
+ij_xml_keep_blank_lines = 1
[pom.xml]
indent_size = 2
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/io/StreamUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/io/StreamUtils.java
index b0badff64ec7..9e10135d87bb 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/io/StreamUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/io/StreamUtils.java
@@ -16,8 +16,13 @@
*/
package org.apache.dubbo.common.io;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
/**
* Stream utils.
@@ -229,4 +234,51 @@ public static void skipUnusedStream(InputStream is) throws IOException {
is.skip(is.available());
}
}
+
+ public static void copy(InputStream in, OutputStream out) throws IOException {
+ if (in.getClass() == ByteArrayInputStream.class) {
+ copy((ByteArrayInputStream) in, out);
+ return;
+ }
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = in.read(buffer)) != -1) {
+ out.write(buffer, 0, bytesRead);
+ }
+ }
+
+ public static void copy(ByteArrayInputStream in, OutputStream out) throws IOException {
+ int len = in.available();
+ byte[] buffer = new byte[len];
+ in.read(buffer, 0, len);
+ out.write(buffer, 0, len);
+ }
+
+ public static byte[] readBytes(InputStream in) throws IOException {
+ if (in.getClass() == ByteArrayInputStream.class) {
+ return readBytes((ByteArrayInputStream) in);
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = in.read(buffer)) != -1) {
+ out.write(buffer, 0, bytesRead);
+ }
+ return out.toByteArray();
+ }
+
+ public static byte[] readBytes(ByteArrayInputStream in) throws IOException {
+ int len = in.available();
+ byte[] bytes = new byte[len];
+ in.read(bytes, 0, len);
+ return bytes;
+ }
+
+ public static String toString(InputStream in) throws IOException {
+ return new String(readBytes(in), StandardCharsets.UTF_8);
+ }
+
+ public static String toString(InputStream in, Charset charset) throws IOException {
+ return new String(readBytes(in), charset);
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java
index df6388c936da..1bcae7a093f1 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java
@@ -24,11 +24,13 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import static java.util.Collections.emptySet;
@@ -404,13 +406,19 @@ public static T first(Collection values) {
return null;
}
if (values instanceof List) {
- List list = (List) values;
- return list.get(0);
+ return ((List) values).get(0);
} else {
return values.iterator().next();
}
}
+ public static T first(List values) {
+ if (isEmpty(values)) {
+ return null;
+ }
+ return values.get(0);
+ }
+
public static Set toTreeSet(Set set) {
if (isEmpty(set)) {
return set;
@@ -420,4 +428,41 @@ public static Set toTreeSet(Set set) {
}
return set;
}
+
+ public static Set newHashSet(int expectedSize) {
+ return new HashSet<>(capacity(expectedSize));
+ }
+
+ public static Set newLinkedHashSet(int expectedSize) {
+ return new LinkedHashSet<>(capacity(expectedSize));
+ }
+
+ public static Set newConcurrentHashSet(int expectedSize) {
+ return Collections.newSetFromMap(newConcurrentHashMap(expectedSize));
+ }
+
+ public static Map newHashMap(int expectedSize) {
+ return new HashMap<>(capacity(expectedSize));
+ }
+
+ public static Map newLinkedHashMap(int expectedSize) {
+ return new LinkedHashMap<>(capacity(expectedSize));
+ }
+
+ public static Map newConcurrentHashMap(int expectedSize) {
+ return new ConcurrentHashMap<>(capacity(expectedSize));
+ }
+
+ public static int capacity(int expectedSize) {
+ if (expectedSize < 3) {
+ if (expectedSize < 0) {
+ throw new IllegalArgumentException("expectedSize cannot be negative but was: " + expectedSize);
+ }
+ return expectedSize + 1;
+ }
+ if (expectedSize < 1 << (Integer.SIZE - 2)) {
+ return (int) (expectedSize / 0.75F + 1.0F);
+ }
+ return Integer.MAX_VALUE;
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRU2Cache.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRU2Cache.java
index 2a725e933434..17450952cf21 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRU2Cache.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRU2Cache.java
@@ -17,15 +17,16 @@
package org.apache.dubbo.common.utils;
import java.util.LinkedHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Function;
/**
* LRU-2
- *
+ *
* When the data accessed for the first time, add it to history list. If the size of history list reaches max capacity, eliminate the earliest data (first in first out).
* When the data already exists in the history list, and be accessed for the second time, then it will be put into cache.
- *
+ *
* TODO, consider replacing with ConcurrentHashMap to improve performance under concurrency
*/
public class LRU2Cache extends LinkedHashMap {
@@ -33,11 +34,10 @@ public class LRU2Cache extends LinkedHashMap {
private static final long serialVersionUID = -5167631809472116969L;
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
-
private static final int DEFAULT_MAX_CAPACITY = 1000;
- private final Lock lock = new ReentrantLock();
- private volatile int maxCapacity;
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private volatile int maxCapacity;
// as history list
private final PreCache preCache;
@@ -58,27 +58,27 @@ protected boolean removeEldestEntry(java.util.Map.Entry eldest) {
@Override
public boolean containsKey(Object key) {
- lock.lock();
+ lock.readLock().lock();
try {
return super.containsKey(key);
} finally {
- lock.unlock();
+ lock.readLock().unlock();
}
}
@Override
public V get(Object key) {
- lock.lock();
+ lock.readLock().lock();
try {
return super.get(key);
} finally {
- lock.unlock();
+ lock.readLock().unlock();
}
}
@Override
public V put(K key, V value) {
- lock.lock();
+ lock.writeLock().lock();
try {
if (preCache.containsKey(key)) {
// add it to cache
@@ -90,39 +90,49 @@ public V put(K key, V value) {
return value;
}
} finally {
- lock.unlock();
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public V computeIfAbsent(K key, Function super K, ? extends V> fn) {
+ V value = get(key);
+ if (value == null) {
+ value = fn.apply(key);
+ put(key, value);
}
+ return value;
}
@Override
public V remove(Object key) {
- lock.lock();
+ lock.writeLock().lock();
try {
preCache.remove(key);
return super.remove(key);
} finally {
- lock.unlock();
+ lock.writeLock().unlock();
}
}
@Override
public int size() {
- lock.lock();
+ lock.readLock().lock();
try {
return super.size();
} finally {
- lock.unlock();
+ lock.readLock().unlock();
}
}
@Override
public void clear() {
- lock.lock();
+ lock.writeLock().lock();
try {
preCache.clear();
super.clear();
} finally {
- lock.unlock();
+ lock.writeLock().unlock();
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java
index 76d6c19cb713..2b0e9c7d56b2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java
@@ -17,8 +17,9 @@
package org.apache.dubbo.common.utils;
import java.util.LinkedHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Function;
/**
* A 'least recently used' cache based on LinkedHashMap.
@@ -31,9 +32,9 @@ public class LRUCache extends LinkedHashMap {
private static final long serialVersionUID = -5167631809472116969L;
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
-
private static final int DEFAULT_MAX_CAPACITY = 1000;
- private final Lock lock = new ReentrantLock();
+
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
private volatile int maxCapacity;
public LRUCache() {
@@ -51,71 +52,85 @@ protected boolean removeEldestEntry(java.util.Map.Entry eldest) {
}
@Override
- public boolean containsKey(Object key) {
- lock.lock();
+ public V get(Object key) {
+ lock.readLock().lock();
try {
- return super.containsKey(key);
+ return super.get(key);
} finally {
- lock.unlock();
+ lock.readLock().unlock();
}
}
@Override
- public V get(Object key) {
- lock.lock();
+ public void clear() {
+ lock.writeLock().lock();
try {
- return super.get(key);
+ super.clear();
} finally {
- lock.unlock();
+ lock.writeLock().unlock();
}
}
@Override
- public V put(K key, V value) {
- lock.lock();
+ public int size() {
+ lock.readLock().lock();
try {
- return super.put(key, value);
+ return super.size();
} finally {
- lock.unlock();
+ lock.readLock().unlock();
}
}
@Override
- public V remove(Object key) {
- lock.lock();
+ public boolean containsKey(Object key) {
+ lock.readLock().lock();
try {
- return super.remove(key);
+ return super.containsKey(key);
} finally {
- lock.unlock();
+ lock.readLock().unlock();
}
}
@Override
- public int size() {
- lock.lock();
+ public V put(K key, V value) {
+ lock.writeLock().lock();
try {
- return super.size();
+ return super.put(key, value);
} finally {
- lock.unlock();
+ lock.writeLock().unlock();
}
}
@Override
- public void clear() {
- lock.lock();
+ public V remove(Object key) {
+ lock.writeLock().lock();
try {
- super.clear();
+ return super.remove(key);
} finally {
- lock.unlock();
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public V computeIfAbsent(K key, Function super K, ? extends V> fn) {
+ V value = get(key);
+ if (value == null) {
+ lock.writeLock().lock();
+ try {
+ return super.computeIfAbsent(key, fn);
+ } finally {
+ lock.writeLock().unlock();
+ }
}
+ return value;
}
public void lock() {
- lock.lock();
+ lock.writeLock().lock();
}
public void releaseLock() {
- lock.unlock();
+ lock.writeLock().unlock();
}
public int getMaxCapacity() {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java
index 0a8cba4bcd42..34cff6af5dc9 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java
@@ -1268,4 +1268,73 @@ public static boolean startsWithIgnoreCase(String str, String prefix) {
// return str.substring(0, prefix.length()).equalsIgnoreCase(prefix);
return str.regionMatches(true, 0, prefix, 0, prefix.length());
}
+
+ public static String substringBefore(String str, int separator) {
+ if (isEmpty(str)) {
+ return str;
+ }
+ int pos = str.indexOf(separator);
+ return pos == INDEX_NOT_FOUND ? str : str.substring(0, pos);
+ }
+
+ public static String substringBefore(String str, String separator) {
+ if (isEmpty(str) || separator == null) {
+ return str;
+ }
+ if (separator.isEmpty()) {
+ return EMPTY_STRING;
+ }
+ int pos = str.indexOf(separator);
+ return pos == INDEX_NOT_FOUND ? str : str.substring(0, pos);
+ }
+
+ /**
+ * Tokenize the given String into a String array.
+ * Trims tokens and omits empty tokens.
+ */
+ public static String[] tokenize(String str, char... separators) {
+ if (isEmpty(str)) {
+ return new String[0];
+ }
+ if (separators == null) {
+ separators = new char[] {','};
+ }
+ List tokens = new ArrayList<>();
+ int start = -1, end = 0;
+ int i = 0;
+ out:
+ for (int len = str.length(), sLen = separators.length; i < len; i++) {
+ char c = str.charAt(i);
+ for (int j = 0; j < sLen; j++) {
+ if (c == separators[j]) {
+ if (start > -1) {
+ tokens.add(str.substring(start, end));
+ start = -1;
+ }
+ continue out;
+ }
+ }
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ default:
+ if (start == -1) {
+ start = i;
+ }
+ end = i + 1;
+ break;
+ }
+ }
+ if (start > -1) {
+ String part = str.substring(start, end);
+ if (tokens.isEmpty()) {
+ return new String[] {part};
+ }
+ tokens.add(part);
+ }
+ return tokens.toArray(new String[0]);
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TimeUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TimeUtils.java
index d6b18476f34b..c21a0de7513d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TimeUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TimeUtils.java
@@ -73,4 +73,29 @@ private static synchronized void startTicker() {
isTickerAlive = true;
}
}
+
+ public static Long parseTimeoutToMills(String timeoutVal) {
+ if (StringUtils.isEmpty(timeoutVal) || StringUtils.isContains(timeoutVal, "null")) {
+ return null;
+ }
+ long value = Long.parseLong(timeoutVal.substring(0, timeoutVal.length() - 1));
+ char unit = timeoutVal.charAt(timeoutVal.length() - 1);
+ switch (unit) {
+ case 'n':
+ return TimeUnit.NANOSECONDS.toMillis(value);
+ case 'u':
+ return TimeUnit.MICROSECONDS.toMillis(value);
+ case 'm':
+ return value;
+ case 'S':
+ return TimeUnit.SECONDS.toMillis(value);
+ case 'M':
+ return TimeUnit.MINUTES.toMillis(value);
+ case 'H':
+ return TimeUnit.HOURS.toMillis(value);
+ default:
+ // invalid timeout config
+ return null;
+ }
+ }
}
diff --git a/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/CreateObserverAdapter.java b/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/CreateObserverAdapter.java
deleted file mode 100644
index 99f44c7cc580..000000000000
--- a/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/CreateObserverAdapter.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 org.apache.dubbo.reactive;
-
-import org.apache.dubbo.rpc.protocol.tri.observer.ServerCallToObserverAdapter;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.mockito.Mockito;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doAnswer;
-
-public class CreateObserverAdapter {
-
- private ServerCallToObserverAdapter responseObserver;
- private AtomicInteger nextCounter;
- private AtomicInteger completeCounter;
- private AtomicInteger errorCounter;
-
- CreateObserverAdapter() {
-
- nextCounter = new AtomicInteger();
- completeCounter = new AtomicInteger();
- errorCounter = new AtomicInteger();
-
- responseObserver = Mockito.mock(ServerCallToObserverAdapter.class);
- doAnswer(o -> nextCounter.incrementAndGet()).when(responseObserver).onNext(anyString());
- doAnswer(o -> completeCounter.incrementAndGet()).when(responseObserver).onCompleted();
- doAnswer(o -> errorCounter.incrementAndGet()).when(responseObserver).onError(any(Throwable.class));
- }
-
- public AtomicInteger getCompleteCounter() {
- return completeCounter;
- }
-
- public AtomicInteger getNextCounter() {
- return nextCounter;
- }
-
- public AtomicInteger getErrorCounter() {
- return errorCounter;
- }
-
- public ServerCallToObserverAdapter getResponseObserver() {
- return this.responseObserver;
- }
-}
diff --git a/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToManyMethodHandlerTest.java b/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToManyMethodHandlerTest.java
deleted file mode 100644
index ddad0dd86f85..000000000000
--- a/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToManyMethodHandlerTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 org.apache.dubbo.reactive;
-
-import org.apache.dubbo.common.stream.StreamObserver;
-import org.apache.dubbo.reactive.handler.ManyToManyMethodHandler;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-/**
- * Unit test for ManyToManyMethodHandler
- */
-public final class ManyToManyMethodHandlerTest {
- @Test
- void testInvoke() throws ExecutionException, InterruptedException {
- CreateObserverAdapter creator = new CreateObserverAdapter();
-
- ManyToManyMethodHandler handler =
- new ManyToManyMethodHandler<>(requestFlux -> requestFlux.map(r -> r + "0"));
- CompletableFuture> future = handler.invoke(new Object[] {creator.getResponseObserver()});
- StreamObserver requestObserver = future.get();
- for (int i = 0; i < 10; i++) {
- requestObserver.onNext(String.valueOf(i));
- }
- requestObserver.onCompleted();
- Assertions.assertEquals(10, creator.getNextCounter().get());
- Assertions.assertEquals(0, creator.getErrorCounter().get());
- Assertions.assertEquals(1, creator.getCompleteCounter().get());
- }
-}
diff --git a/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToOneMethodHandlerTest.java b/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToOneMethodHandlerTest.java
deleted file mode 100644
index 693d4cce6237..000000000000
--- a/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToOneMethodHandlerTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 org.apache.dubbo.reactive;
-
-import org.apache.dubbo.common.stream.StreamObserver;
-import org.apache.dubbo.reactive.handler.ManyToOneMethodHandler;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-/**
- * Unit test for ManyToOneMethodHandler
- */
-public final class ManyToOneMethodHandlerTest {
-
- private StreamObserver requestObserver;
- private CreateObserverAdapter creator;
-
- @BeforeEach
- void init() throws ExecutionException, InterruptedException {
- creator = new CreateObserverAdapter();
- ManyToOneMethodHandler handler = new ManyToOneMethodHandler<>(requestFlux ->
- requestFlux.map(Integer::valueOf).reduce(Integer::sum).map(String::valueOf));
- CompletableFuture> future = handler.invoke(new Object[] {creator.getResponseObserver()});
- requestObserver = future.get();
- }
-
- @Test
- void testInvoker() {
- for (int i = 0; i < 10; i++) {
- requestObserver.onNext(String.valueOf(i));
- }
- requestObserver.onCompleted();
- Assertions.assertEquals(1, creator.getNextCounter().get());
- Assertions.assertEquals(0, creator.getErrorCounter().get());
- Assertions.assertEquals(1, creator.getCompleteCounter().get());
- }
-
- @Test
- void testError() {
- for (int i = 0; i < 10; i++) {
- if (i == 6) {
- requestObserver.onError(new Throwable());
- }
- requestObserver.onNext(String.valueOf(i));
- }
- requestObserver.onCompleted();
- Assertions.assertEquals(0, creator.getNextCounter().get());
- Assertions.assertEquals(1, creator.getErrorCounter().get());
- Assertions.assertEquals(0, creator.getCompleteCounter().get());
- }
-}
diff --git a/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/OneToManyMethodHandlerTest.java b/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/OneToManyMethodHandlerTest.java
deleted file mode 100644
index e81e0a77c7c3..000000000000
--- a/dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/OneToManyMethodHandlerTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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 org.apache.dubbo.reactive;
-
-import org.apache.dubbo.reactive.handler.OneToManyMethodHandler;
-
-import java.util.concurrent.CompletableFuture;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import reactor.core.publisher.Flux;
-
-/**
- * Unit test for OneToManyMethodHandler
- */
-public final class OneToManyMethodHandlerTest {
-
- private CreateObserverAdapter creator;
-
- @BeforeEach
- void init() {
- creator = new CreateObserverAdapter();
- }
-
- @Test
- void testInvoke() {
- String request = "1,2,3,4,5,6,7";
- OneToManyMethodHandler handler =
- new OneToManyMethodHandler<>(requestMono -> requestMono.flatMapMany(r -> Flux.fromArray(r.split(","))));
- CompletableFuture> future = handler.invoke(new Object[] {request, creator.getResponseObserver()});
- Assertions.assertTrue(future.isDone());
- Assertions.assertEquals(7, creator.getNextCounter().get());
- Assertions.assertEquals(0, creator.getErrorCounter().get());
- Assertions.assertEquals(1, creator.getCompleteCounter().get());
- }
-
- @Test
- void testError() {
- String request = "1,2,3,4,5,6,7";
- OneToManyMethodHandler handler =
- new OneToManyMethodHandler<>(requestMono -> Flux.create(emitter -> {
- for (int i = 0; i < 10; i++) {
- if (i == 6) {
- emitter.error(new Throwable());
- } else {
- emitter.next(String.valueOf(i));
- }
- }
- }));
- CompletableFuture> future = handler.invoke(new Object[] {request, creator.getResponseObserver()});
- Assertions.assertTrue(future.isDone());
- Assertions.assertEquals(6, creator.getNextCounter().get());
- Assertions.assertEquals(1, creator.getErrorCounter().get());
- Assertions.assertEquals(0, creator.getCompleteCounter().get());
- }
-}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java
index d13c4feeec0e..ffcbb1797de0 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java
@@ -20,6 +20,9 @@
import org.apache.dubbo.remoting.http12.exception.HttpStatusException;
import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;
+import java.util.List;
+import java.util.Map;
+
public abstract class AbstractServerHttpChannelObserver implements CustomizableHttpChannelObserver {
private HeadersCustomizer headersCustomizer = HeadersCustomizer.NO_OP;
@@ -72,12 +75,19 @@ protected TrailersCustomizer getTrailersCustomizer() {
@Override
public void onNext(Object data) {
try {
+ if (data instanceof HttpResult) {
+ HttpResult> result = (HttpResult>) data;
+ if (!headerSent) {
+ doSendHeaders(String.valueOf(result.getStatus()), result.getHeaders());
+ }
+ data = result.getBody();
+ }
if (!headerSent) {
- doSendHeaders(HttpStatus.OK.getStatusString());
+ doSendHeaders(HttpStatus.OK.getStatusString(), null);
}
HttpOutputMessage outputMessage = encodeHttpOutputMessage(data);
preOutputMessage(outputMessage);
- this.responseEncoder.encode(outputMessage.getBody(), data);
+ responseEncoder.encode(outputMessage.getBody(), data);
getHttpChannel().writeMessage(outputMessage);
postOutputMessage(outputMessage);
} catch (Throwable e) {
@@ -106,15 +116,15 @@ public void onError(Throwable throwable) {
httpStatusCode = ((HttpStatusException) throwable).getStatusCode();
}
if (!headerSent) {
- doSendHeaders(String.valueOf(httpStatusCode));
+ doSendHeaders(String.valueOf(httpStatusCode), null);
}
try {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setStatus(String.valueOf(httpStatusCode));
errorResponse.setMessage(throwable.getMessage());
- this.errorResponseCustomizer.accept(errorResponse, throwable);
+ errorResponseCustomizer.accept(errorResponse, throwable);
HttpOutputMessage httpOutputMessage = encodeHttpOutputMessage(errorResponse);
- this.responseEncoder.encode(httpOutputMessage.getBody(), errorResponse);
+ responseEncoder.encode(httpOutputMessage.getBody(), errorResponse);
getHttpChannel().writeMessage(httpOutputMessage);
} catch (Throwable ex) {
throwable = new EncodeException(ex);
@@ -133,17 +143,19 @@ public HttpChannel getHttpChannel() {
return httpChannel;
}
- private void doSendHeaders(String statusCode) {
+ private void doSendHeaders(String statusCode, Map> additionalHeaders) {
HttpMetadata httpMetadata = encodeHttpMetadata();
- httpMetadata.headers().set(HttpHeaderNames.STATUS.getName(), statusCode);
- httpMetadata
- .headers()
- .set(
- HttpHeaderNames.CONTENT_TYPE.getName(),
- responseEncoder.mediaType().getName());
- this.headersCustomizer.accept(httpMetadata.headers());
+ HttpHeaders headers = httpMetadata.headers();
+ headers.set(HttpHeaderNames.STATUS.getName(), statusCode);
+ headers.set(
+ HttpHeaderNames.CONTENT_TYPE.getName(),
+ responseEncoder.mediaType().getName());
+ headersCustomizer.accept(headers);
+ if (additionalHeaders != null) {
+ headers.putAll(additionalHeaders);
+ }
getHttpChannel().writeHeader(httpMetadata);
- this.headerSent = true;
+ headerSent = true;
}
protected void doOnCompleted(Throwable throwable) {
@@ -151,7 +163,7 @@ protected void doOnCompleted(Throwable throwable) {
if (httpMetadata == null) {
return;
}
- this.trailersCustomizer.accept(httpMetadata.headers(), throwable);
+ trailersCustomizer.accept(httpMetadata.headers(), throwable);
getHttpChannel().writeHeader(httpMetadata);
}
}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannel.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannel.java
index 795bf8ee3773..67c2a1cfebb9 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannel.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannel.java
@@ -29,5 +29,7 @@ public interface HttpChannel {
SocketAddress remoteAddress();
+ SocketAddress localAddress();
+
void flush();
}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpCookie.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpCookie.java
new file mode 100644
index 000000000000..4a310d50dadf
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpCookie.java
@@ -0,0 +1,123 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12;
+
+import org.apache.dubbo.common.utils.Assert;
+import org.apache.dubbo.common.utils.StringUtils;
+
+public final class HttpCookie {
+
+ private final String name;
+ private String value;
+ private String domain;
+ private String path;
+ private long maxAge = Long.MIN_VALUE;
+ private boolean secure;
+ private boolean httpOnly;
+ private String sameSite;
+
+ public HttpCookie(String name, String value) {
+ name = StringUtils.trim(name);
+ Assert.notEmptyString(name, "name is required");
+ this.name = name.trim();
+ setValue(value);
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String value() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ Assert.notNull(name, "value can not be null");
+ this.value = value;
+ }
+
+ public String domain() {
+ return domain;
+ }
+
+ public void setDomain(String domain) {
+ this.domain = domain;
+ }
+
+ public String path() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public long maxAge() {
+ return maxAge;
+ }
+
+ public void setMaxAge(long maxAge) {
+ this.maxAge = maxAge;
+ }
+
+ public boolean secure() {
+ return secure;
+ }
+
+ public void setSecure(boolean secure) {
+ this.secure = secure;
+ }
+
+ public boolean httpOnly() {
+ return httpOnly;
+ }
+
+ public void setHttpOnly(boolean httpOnly) {
+ this.httpOnly = httpOnly;
+ }
+
+ public String sameSite() {
+ return sameSite;
+ }
+
+ public void setSameSite(String sameSite) {
+ this.sameSite = sameSite;
+ }
+
+ public String toString() {
+ StringBuilder buf = new StringBuilder(name).append('=').append(value);
+ if (domain != null) {
+ buf.append(", domain=").append(domain);
+ }
+ if (path != null) {
+ buf.append(", path=").append(path);
+ }
+ if (maxAge >= 0) {
+ buf.append(", maxAge=").append(maxAge).append('s');
+ }
+ if (secure) {
+ buf.append(", secure");
+ }
+ if (httpOnly) {
+ buf.append(", HTTPOnly");
+ }
+ if (sameSite != null) {
+ buf.append(", SameSite=").append(sameSite);
+ }
+ return buf.toString();
+ }
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java
new file mode 100644
index 000000000000..8032c6295398
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java
@@ -0,0 +1,60 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12;
+
+import java.nio.charset.StandardCharsets;
+
+public enum HttpMethods {
+ GET,
+ POST,
+ PUT,
+ DELETE,
+ HEAD,
+ OPTIONS,
+ PATCH,
+ TRACE;
+
+ public static final byte[][] HTTP_METHODS_BYTES;
+
+ static {
+ HttpMethods[] methods = values();
+ int len = methods.length;
+ HTTP_METHODS_BYTES = new byte[len][];
+ for (int i = 0; i < len; i++) {
+ HTTP_METHODS_BYTES[i] = methods[i].name().getBytes(StandardCharsets.ISO_8859_1);
+ }
+ }
+
+ @SuppressWarnings("StringEquality")
+ public static HttpMethods of(String name) {
+ // fast-path
+ if (name == GET.name()) {
+ return GET;
+ } else if (name == POST.name()) {
+ return POST;
+ }
+ return valueOf(name);
+ }
+
+ public static boolean isGet(String name) {
+ return GET.name().equals(name);
+ }
+
+ public static boolean isPost(String name) {
+ return POST.name().equals(name);
+ }
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpRequest.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpRequest.java
new file mode 100644
index 000000000000..904e01320a9f
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpRequest.java
@@ -0,0 +1,134 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12;
+
+import java.io.InputStream;
+import java.util.*;
+
+public interface HttpRequest extends RequestMetadata {
+
+ boolean IsHttp2();
+
+ String method();
+
+ void setMethod(String method);
+
+ String uri();
+
+ void setUri(String uri);
+
+ String path();
+
+ String query();
+
+ String header(String name);
+
+ List headerValues(String name);
+
+ Date dateHeader(String name);
+
+ boolean hasHeader(String name);
+
+ Collection headerNames();
+
+ HttpHeaders headers();
+
+ void setHeader(String name, String value);
+
+ void setHeader(String name, List value);
+
+ void setHeader(String name, Date value);
+
+ Collection cookies();
+
+ HttpCookie cookie(String name);
+
+ String contentType();
+
+ void setContentType(String contentType);
+
+ int contentLength();
+
+ String mediaType();
+
+ String charset();
+
+ List accept();
+
+ Locale locale();
+
+ List locales();
+
+ String scheme();
+
+ String serverHost();
+
+ String serverName();
+
+ int serverPort();
+
+ String remoteHost();
+
+ String remoteAddr();
+
+ int remotePort();
+
+ String localHost();
+
+ String localAddr();
+
+ int localPort();
+
+ String parameter(String name);
+
+ String parameter(String name, String defaultValue);
+
+ List parameterValues(String name);
+
+ Collection parameterNames();
+
+ Collection parts();
+
+ FileUpload part(String name);
+
+ Object attribute(String name);
+
+ T attribute(String name, Class type);
+
+ void setAttribute(String name, Object value);
+
+ Collection attributeNames();
+
+ Map attributes();
+
+ InputStream inputStream();
+
+ void setInputStream(InputStream is);
+
+ interface FileUpload {
+
+ String name();
+
+ String filename();
+
+ String contentType();
+
+ int size();
+
+ InputStream inputStream();
+ }
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResponse.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResponse.java
new file mode 100644
index 000000000000..41ef10e589ea
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResponse.java
@@ -0,0 +1,85 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12;
+
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+public interface HttpResponse {
+
+ int status();
+
+ void setStatus(int status);
+
+ String header(String name);
+
+ List headerValues(String name);
+
+ Date dateHeader(String name);
+
+ boolean hasHeader(String name);
+
+ Collection headerNames();
+
+ HttpHeaders headers();
+
+ void addHeader(String name, String value);
+
+ void setHeader(String name, String value);
+
+ void setHeader(String name, List value);
+
+ void setHeader(String name, Date value);
+
+ void addCookie(HttpCookie cookie);
+
+ String contentType();
+
+ void setContentType(String contentType);
+
+ String mediaType();
+
+ String charset();
+
+ String locale();
+
+ void setLocale(String locale);
+
+ OutputStream outputStream();
+
+ void setOutputStream(OutputStream os);
+
+ Object body();
+
+ void setBody(Object body);
+
+ void sendRedirect(String location);
+
+ void sendError(int status);
+
+ void sendError(int status, String message);
+
+ boolean isCommitted();
+
+ void commit();
+
+ void reset();
+
+ void resetBuffer();
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResult.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResult.java
new file mode 100644
index 000000000000..2b6a00d21ad9
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResult.java
@@ -0,0 +1,29 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12;
+
+import java.util.List;
+import java.util.Map;
+
+public interface HttpResult {
+
+ int getStatus();
+
+ Map> getHeaders();
+
+ T getBody();
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java
new file mode 100644
index 000000000000..888f924e6fa3
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java
@@ -0,0 +1,195 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12;
+
+import org.apache.dubbo.common.io.StreamUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.remoting.http12.exception.DecodeException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufInputStream;
+import io.netty.buffer.Unpooled;
+import io.netty.handler.codec.http.DefaultFullHttpRequest;
+import io.netty.handler.codec.http.DefaultHttpHeaders;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.codec.http.cookie.Cookie;
+import io.netty.handler.codec.http.cookie.CookieHeaderNames.SameSite;
+import io.netty.handler.codec.http.cookie.DefaultCookie;
+import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
+import io.netty.handler.codec.http.cookie.ServerCookieEncoder;
+import io.netty.handler.codec.http.multipart.Attribute;
+import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
+import io.netty.handler.codec.http.multipart.FileUpload;
+import io.netty.handler.codec.http.multipart.HttpDataFactory;
+import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
+import io.netty.handler.codec.http.multipart.InterfaceHttpData;
+
+public final class HttpUtils {
+
+ public static final HttpDataFactory DATA_FACTORY = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);
+
+ private HttpUtils() {}
+
+ public static List decodeCookies(String value) {
+ List cookies = new ArrayList<>();
+ for (Cookie c : ServerCookieDecoder.LAX.decodeAll(value)) {
+ cookies.add(new HttpCookie(c.name(), c.value()));
+ }
+ return cookies;
+ }
+
+ public static List encodeCookies(Collection cookies) {
+ List encodedCookies = new ArrayList<>(cookies.size());
+ for (HttpCookie cookie : cookies) {
+ DefaultCookie c = new DefaultCookie(cookie.name(), cookie.value());
+ c.setPath(cookie.path());
+ c.setDomain(cookie.domain());
+ c.setMaxAge(cookie.maxAge());
+ c.setSecure(cookie.secure());
+ c.setHttpOnly(cookie.httpOnly());
+ c.setSameSite(SameSite.valueOf(cookie.sameSite()));
+ encodedCookies.add(ServerCookieEncoder.LAX.encode(c));
+ }
+ return encodedCookies;
+ }
+
+ public static List parseAccept(String header) {
+ Map locales = new TreeMap<>();
+ if (header == null) {
+ return Collections.emptyList();
+ }
+ for (String item : StringUtils.tokenize(header, ',')) {
+ String[] pair = StringUtils.tokenize(item, ';');
+ locales.put(pair.length > 1 ? Float.parseFloat(pair[1]) : 1.0F, pair[0]);
+ }
+ return new ArrayList<>(locales.values());
+ }
+
+ public static List parseAcceptLanguage(String header) {
+ Map locales = new TreeMap<>();
+ if (header == null) {
+ return Collections.emptyList();
+ }
+ for (String item : StringUtils.tokenize(header, ',')) {
+ String[] pair = StringUtils.tokenize(item, ';');
+ Locale locale;
+ String[] parts = StringUtils.tokenize(pair[0], '-', '_');
+ switch (parts.length) {
+ case 2:
+ locale = new Locale(parts[0], parts[1]);
+ break;
+ case 3:
+ locale = new Locale(parts[0], parts[1], parts[2]);
+ break;
+ default:
+ locale = new Locale(parts[0]);
+ break;
+ }
+ locales.put(pair.length > 1 ? Float.parseFloat(pair[1]) : 1.0F, locale);
+ }
+ return new ArrayList<>(locales.values());
+ }
+
+ public static HttpPostRequestDecoder createPostRequestDecoder(
+ HttpRequest request, InputStream inputStream, String charset) {
+ ByteBuf data;
+ try {
+ data = Unpooled.wrappedBuffer(StreamUtils.readBytes(inputStream));
+ } catch (IOException e) {
+ throw new DecodeException("Error while reading post data: " + e.getMessage(), e);
+ } finally {
+ try {
+ inputStream.close();
+ } catch (IOException ignored) {
+ }
+ }
+ DefaultFullHttpRequest nRequest = new DefaultFullHttpRequest(
+ HttpVersion.HTTP_1_1,
+ HttpMethod.POST,
+ request.uri(),
+ data,
+ new DefaultHttpHeaders(),
+ new DefaultHttpHeaders(false));
+ request.headers().forEach(nRequest.headers()::set);
+ if (charset == null) {
+ return new HttpPostRequestDecoder(DATA_FACTORY, nRequest);
+ } else {
+ return new HttpPostRequestDecoder(DATA_FACTORY, nRequest, Charset.forName(charset));
+ }
+ }
+
+ public static String readPostValue(InterfaceHttpData item) {
+ try {
+ return ((Attribute) item).getValue();
+ } catch (IOException e) {
+ throw new DecodeException("Error while reading post value: " + e.getMessage(), e);
+ }
+ }
+
+ public static HttpRequest.FileUpload readUpload(InterfaceHttpData item) {
+ return new DefaultFileUploadAdaptee((FileUpload) item);
+ }
+
+ private static class DefaultFileUploadAdaptee implements HttpRequest.FileUpload {
+ private final FileUpload fu;
+ private InputStream inputStream;
+
+ public DefaultFileUploadAdaptee(FileUpload fu) {
+ this.fu = fu;
+ }
+
+ @Override
+ public String name() {
+ return fu.getName();
+ }
+
+ @Override
+ public String filename() {
+ return fu.getFilename();
+ }
+
+ @Override
+ public String contentType() {
+ return fu.getContentType();
+ }
+
+ @Override
+ public int size() {
+ return (int) fu.length();
+ }
+
+ @Override
+ public InputStream inputStream() {
+ if (inputStream == null) {
+ inputStream = new ByteBufInputStream(fu.content());
+ }
+ return inputStream;
+ }
+ }
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/DecodeException.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/DecodeException.java
index af426da47d4e..78dfa937347a 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/DecodeException.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/DecodeException.java
@@ -29,4 +29,8 @@ public DecodeException(String message) {
public DecodeException(Throwable cause) {
super(500, cause);
}
+
+ public DecodeException(String message, Throwable cause) {
+ super(500, message, cause);
+ }
}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/HttpStatusException.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/HttpStatusException.java
index dd9104aa5fc1..bf86615da11b 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/HttpStatusException.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/HttpStatusException.java
@@ -34,6 +34,11 @@ public HttpStatusException(int statusCode, Throwable cause) {
this.statusCode = statusCode;
}
+ public HttpStatusException(int statusCode, String message, Throwable cause) {
+ super(message, cause);
+ this.statusCode = statusCode;
+ }
+
public int getStatusCode() {
return statusCode;
}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ChannelDelegate.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ChannelDelegate.java
index 9c5aaea10426..994ceaee9659 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ChannelDelegate.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ChannelDelegate.java
@@ -49,6 +49,11 @@ public SocketAddress remoteAddress() {
return h2StreamChannel.remoteAddress();
}
+ @Override
+ public SocketAddress localAddress() {
+ return h2StreamChannel.localAddress();
+ }
+
@Override
public void flush() {
h2StreamChannel.flush();
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpMessageAdapterFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpMessageAdapterFactory.java
new file mode 100644
index 000000000000..ce07adc5caad
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpMessageAdapterFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12.message;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.remoting.http12.HttpChannel;
+import org.apache.dubbo.remoting.http12.HttpMetadata;
+import org.apache.dubbo.remoting.http12.HttpResponse;
+
+@Activate
+public final class DefaultHttpMessageAdapterFactory
+ implements HttpMessageAdapterFactory {
+
+ @Override
+ public DefaultHttpRequest adapterRequest(HttpMetadata rawRequest, HttpChannel channel) {
+ return new DefaultHttpRequest(rawRequest, channel);
+ }
+
+ @Override
+ public HttpResponse adapterResponse(DefaultHttpRequest request, HttpMetadata rawRequest, Void rawResponse) {
+ return null;
+ }
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java
new file mode 100644
index 000000000000..27b7b51d2e53
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java
@@ -0,0 +1,539 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12.message;
+
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.remoting.http12.HttpChannel;
+import org.apache.dubbo.remoting.http12.HttpCookie;
+import org.apache.dubbo.remoting.http12.HttpHeaderNames;
+import org.apache.dubbo.remoting.http12.HttpHeaders;
+import org.apache.dubbo.remoting.http12.HttpMetadata;
+import org.apache.dubbo.remoting.http12.HttpMethods;
+import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.remoting.http12.HttpUtils;
+import org.apache.dubbo.remoting.http12.RequestMetadata;
+import org.apache.dubbo.remoting.http12.h2.Http2Header;
+
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import io.netty.handler.codec.DateFormatter;
+import io.netty.handler.codec.http.QueryStringDecoder;
+import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
+import io.netty.handler.codec.http.multipart.InterfaceHttpData;
+import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
+
+public class DefaultHttpRequest implements HttpRequest {
+
+ private final HttpMetadata metadata;
+ private final HttpChannel channel;
+ private final HttpHeaders headers;
+
+ private String method;
+ private String uri;
+ private List cookies;
+ private String contentType;
+ private List accept;
+ private List locales;
+ private QueryStringDecoder decoder;
+ private HttpPostRequestDecoder postDecoder;
+ private boolean postParsed;
+ private Map attributes;
+ private InputStream inputStream;
+
+ public DefaultHttpRequest(HttpMetadata metadata, HttpChannel channel) {
+ this.metadata = metadata;
+ this.channel = channel;
+ headers = metadata.headers();
+ if (metadata instanceof RequestMetadata) {
+ RequestMetadata requestMetadata = (RequestMetadata) metadata;
+ method = requestMetadata.method();
+ uri = requestMetadata.path();
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public boolean IsHttp2() {
+ return metadata instanceof Http2Header;
+ }
+
+ @Override
+ public String method() {
+ return method;
+ }
+
+ @Override
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ @Override
+ public String uri() {
+ return uri;
+ }
+
+ @Override
+ public void setUri(String uri) {
+ this.uri = uri;
+ decoder = null;
+ postDecoder = null;
+ postParsed = false;
+ }
+
+ @Override
+ public String path() {
+ return getDecoder().path();
+ }
+
+ @Override
+ public String query() {
+ return getDecoder().rawQuery();
+ }
+
+ @Override
+ public String header(String name) {
+ return headers.getFirst(name);
+ }
+
+ @Override
+ public List headerValues(String name) {
+ return headers.get(name);
+ }
+
+ @Override
+ public Date dateHeader(String name) {
+ String value = headers.getFirst(name);
+ return StringUtils.isEmpty(value) ? null : DateFormatter.parseHttpDate(value);
+ }
+
+ @Override
+ public boolean hasHeader(String name) {
+ return headers.containsKey(name);
+ }
+
+ @Override
+ public Collection headerNames() {
+ return headers.keySet();
+ }
+
+ @Override
+ public HttpHeaders headers() {
+ return headers;
+ }
+
+ @Override
+ public void setHeader(String name, String value) {
+ headers.set(name, value);
+ }
+
+ @Override
+ public void setHeader(String name, Date value) {
+ headers.set(name, DateFormatter.format(value));
+ }
+
+ @Override
+ public void setHeader(String name, List value) {
+ headers.put(name, value);
+ }
+
+ @Override
+ public Collection cookies() {
+ if (cookies == null) {
+ parseCookies();
+ }
+ return cookies;
+ }
+
+ @Override
+ public HttpCookie cookie(String name) {
+ if (cookies == null) {
+ parseCookies();
+ }
+ for (int i = 0, len = cookies.size(); i < len; i++) {
+ HttpCookie cookie = cookies.get(i);
+ if (cookie.name().equals(name)) {
+ return cookie;
+ }
+ }
+ return null;
+ }
+
+ private void parseCookies() {
+ cookies = HttpUtils.decodeCookies(headers.getFirst("cookie"));
+ }
+
+ @Override
+ public String contentType() {
+ return getContentType0();
+ }
+
+ private String getContentType0() {
+ if (contentType == null) {
+ String value = headers.getFirst(HttpHeaderNames.CONTENT_TYPE.getName());
+ contentType = value == null ? StringUtils.EMPTY_STRING : value.trim();
+ }
+ return contentType.isEmpty() ? null : contentType;
+ }
+
+ @Override
+ public void setContentType(String contentType) {
+ this.contentType = contentType == null ? StringUtils.EMPTY_STRING : contentType.trim();
+ headers.set(HttpHeaderNames.CONTENT_TYPE.getName(), getContentType0());
+ }
+
+ @Override
+ public int contentLength() {
+ String value = headers.getFirst(HttpHeaderNames.CONTENT_LENGTH.getName());
+ return value == null ? 0 : Integer.parseInt(value);
+ }
+
+ @Override
+ public String mediaType() {
+ String contentType = getContentType0();
+ if (contentType == null) {
+ return null;
+ }
+ int pos = contentType.indexOf(';');
+ return pos == -1 ? contentType : contentType.substring(0, pos).trim();
+ }
+
+ @Override
+ public String charset() {
+ String charset = getCharset0();
+ return charset == null ? StandardCharsets.UTF_8.name() : charset;
+ }
+
+ private String getCharset0() {
+ String contentType = getContentType0();
+ if (contentType == null) {
+ return null;
+ }
+ int pos = contentType.lastIndexOf("charset=");
+ return pos == -1 ? null : contentType.substring(pos + 8);
+ }
+
+ @Override
+ public List accept() {
+ if (accept == null) {
+ accept = HttpUtils.parseAccept(headers.getFirst("accept-language"));
+ }
+ return accept;
+ }
+
+ @Override
+ public Locale locale() {
+ return locales().get(0);
+ }
+
+ @Override
+ public List locales() {
+ if (locales == null) {
+ locales = HttpUtils.parseAcceptLanguage(headers.getFirst("accept-language"));
+ if (locales.isEmpty()) {
+ locales.add(Locale.getDefault());
+ }
+ }
+ return locales;
+ }
+
+ @Override
+ public String scheme() {
+ String scheme = headers.getFirst("x-forwarded-proto");
+ if (IsHttp2()) {
+ scheme = headers.getFirst(":scheme");
+ }
+ return scheme == null ? "https" : scheme;
+ }
+
+ @Override
+ public String serverHost() {
+ String host = getHost0();
+ return host == null ? localHost() + ':' + localPort() : host;
+ }
+
+ @Override
+ public String serverName() {
+ String host = getHost0();
+ if (host != null) {
+ int pos = host.lastIndexOf(':');
+ return pos == -1 ? host : host.substring(0, pos);
+ }
+ return localHost();
+ }
+
+ @Override
+ public int serverPort() {
+ String port = headers.getFirst("x-forwarded-port");
+ if (port != null) {
+ return Integer.parseInt(port);
+ }
+ String host = getHost0();
+ if (host != null) {
+ int pos = host.lastIndexOf(':');
+ return pos == -1 ? -1 : Integer.parseInt(host.substring(0, pos));
+ }
+ return localPort();
+ }
+
+ private String getHost0() {
+ return headers.getFirst(IsHttp2() ? ":authority" : "host");
+ }
+
+ @Override
+ public String remoteHost() {
+ return getRemoteAddress().getAddress().getHostName();
+ }
+
+ @Override
+ public String remoteAddr() {
+ return getRemoteAddress().getAddress().getHostAddress();
+ }
+
+ @Override
+ public int remotePort() {
+ return getRemoteAddress().getPort();
+ }
+
+ private InetSocketAddress getRemoteAddress() {
+ return (InetSocketAddress) channel.remoteAddress();
+ }
+
+ @Override
+ public String localHost() {
+ return getLocalAddress().getAddress().getHostAddress();
+ }
+
+ @Override
+ public String localAddr() {
+ return getLocalAddress().getAddress().getHostAddress();
+ }
+
+ @Override
+ public int localPort() {
+ return getLocalAddress().getPort();
+ }
+
+ private InetSocketAddress getLocalAddress() {
+ return (InetSocketAddress) channel.localAddress();
+ }
+
+ @Override
+ public String parameter(String name) {
+ List values = getDecoder().parameters().get(name);
+ if (CollectionUtils.isNotEmpty(values)) {
+ return values.get(0);
+ }
+ HttpPostRequestDecoder postDecoder = getPostDecoder();
+ if (postDecoder == null) {
+ return null;
+ }
+ List items = postDecoder.getBodyHttpDatas(name);
+ if (items == null) {
+ return null;
+ }
+ for (int i = 0, len = items.size(); i < len; i++) {
+ InterfaceHttpData item = items.get(i);
+ if (item.getHttpDataType() == HttpDataType.Attribute) {
+ return HttpUtils.readPostValue(item);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String parameter(String name, String defaultValue) {
+ String value = parameter(name);
+ return value == null ? defaultValue : value;
+ }
+
+ @Override
+ public List parameterValues(String name) {
+ List values = getDecoder().parameters().get(name);
+ HttpPostRequestDecoder postDecoder = getPostDecoder();
+ if (postDecoder == null) {
+ return values;
+ }
+ List items = postDecoder.getBodyHttpDatas(name);
+ if (items == null) {
+ return values;
+ }
+ for (int i = 0, len = items.size(); i < len; i++) {
+ InterfaceHttpData item = items.get(i);
+ if (item.getHttpDataType() == HttpDataType.Attribute) {
+ if (values == null) {
+ values = new ArrayList<>();
+ }
+ values.add(HttpUtils.readPostValue(item));
+ }
+ }
+ return values;
+ }
+
+ @Override
+ public Collection parameterNames() {
+ Set names = getDecoder().parameters().keySet();
+ HttpPostRequestDecoder postDecoder = getPostDecoder();
+ if (postDecoder == null) {
+ return names;
+ }
+ List items = postDecoder.getBodyHttpDatas();
+ if (items == null) {
+ return names;
+ }
+ Set allNames = null;
+ for (int i = 0, len = items.size(); i < len; i++) {
+ InterfaceHttpData item = items.get(i);
+ if (item.getHttpDataType() == HttpDataType.Attribute) {
+ if (allNames == null) {
+ allNames = new LinkedHashSet<>(names);
+ }
+ allNames.add(item.getName());
+ }
+ }
+ return allNames;
+ }
+
+ @Override
+ public Collection parts() {
+ HttpPostRequestDecoder postDecoder = getPostDecoder();
+ if (postDecoder == null) {
+ return Collections.emptyList();
+ }
+ List items = postDecoder.getBodyHttpDatas();
+ if (items == null) {
+ return Collections.emptyList();
+ }
+ List fileUploads = new ArrayList<>();
+ for (int i = 0, len = items.size(); i < len; i++) {
+ InterfaceHttpData item = items.get(i);
+ if (item.getHttpDataType() == HttpDataType.FileUpload) {
+ fileUploads.add(HttpUtils.readUpload(item));
+ }
+ }
+ return fileUploads;
+ }
+
+ @Override
+ public FileUpload part(String name) {
+ HttpPostRequestDecoder postDecoder = getPostDecoder();
+ if (postDecoder == null) {
+ return null;
+ }
+ List items = postDecoder.getBodyHttpDatas(name);
+ if (items == null) {
+ return null;
+ }
+
+ for (int i = 0, len = items.size(); i < len; i++) {
+ InterfaceHttpData item = items.get(i);
+ if (item.getHttpDataType() == HttpDataType.FileUpload) {
+ return HttpUtils.readUpload(item);
+ }
+ }
+ return null;
+ }
+
+ private QueryStringDecoder getDecoder() {
+ if (decoder == null) {
+ String charset = getCharset0();
+ if (charset == null) {
+ decoder = new QueryStringDecoder(uri);
+ } else {
+ decoder = new QueryStringDecoder(uri, Charset.forName(charset));
+ }
+ }
+ return decoder;
+ }
+
+ private HttpPostRequestDecoder getPostDecoder() {
+ if (inputStream == null) {
+ return null;
+ }
+ if (postDecoder == null) {
+ if (postParsed) {
+ return null;
+ }
+ if (HttpMethods.isPost(method)) {
+ postDecoder = HttpUtils.createPostRequestDecoder(this, inputStream, getCharset0());
+ }
+ postParsed = true;
+ }
+ return postDecoder;
+ }
+
+ @Override
+ public Object attribute(String name) {
+ return getAttributes().get(name);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T attribute(String name, Class type) {
+ return (T) getAttributes().get(name);
+ }
+
+ @Override
+ public void setAttribute(String name, Object value) {
+ getAttributes().put(name, value);
+ }
+
+ @Override
+ public Collection attributeNames() {
+ return getAttributes().keySet();
+ }
+
+ @Override
+ public Map attributes() {
+ return getAttributes();
+ }
+
+ private Map getAttributes() {
+ if (attributes == null) {
+ attributes = new HashMap<>();
+ }
+ return attributes;
+ }
+
+ @Override
+ public InputStream inputStream() {
+ return inputStream;
+ }
+
+ @Override
+ public void setInputStream(InputStream is) {
+ inputStream = is;
+ if (HttpMethods.isPost(method)) {
+ postDecoder = null;
+ postParsed = false;
+ }
+ }
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResponse.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResponse.java
new file mode 100644
index 000000000000..5a33624ec56d
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResponse.java
@@ -0,0 +1,270 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12.message;
+
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.remoting.http12.HttpCookie;
+import org.apache.dubbo.remoting.http12.HttpHeaderNames;
+import org.apache.dubbo.remoting.http12.HttpHeaders;
+import org.apache.dubbo.remoting.http12.HttpResponse;
+import org.apache.dubbo.remoting.http12.HttpResult;
+import org.apache.dubbo.remoting.http12.HttpUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import io.netty.handler.codec.DateFormatter;
+
+public class DefaultHttpResponse implements HttpResponse, HttpResult {
+
+ private final AtomicBoolean committed = new AtomicBoolean();
+ private final HttpHeaders headers = new HttpHeaders();
+
+ private int status;
+ private String contentType;
+ private List cookies;
+ private OutputStream outputStream;
+ private Object body;
+
+ @Override
+ public int status() {
+ return status;
+ }
+
+ @Override
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ @Override
+ public String header(String name) {
+ return headers.getFirst(name);
+ }
+
+ @Override
+ public List headerValues(String name) {
+ return headers.get(name);
+ }
+
+ @Override
+ public Date dateHeader(String name) {
+ String value = headers.getFirst(name);
+ return StringUtils.isEmpty(value) ? null : DateFormatter.parseHttpDate(value);
+ }
+
+ @Override
+ public boolean hasHeader(String name) {
+ return headers.containsKey(name);
+ }
+
+ @Override
+ public Collection headerNames() {
+ return headers.keySet();
+ }
+
+ @Override
+ public HttpHeaders headers() {
+ return headers;
+ }
+
+ @Override
+ public void addHeader(String name, String value) {
+ headers.computeIfAbsent(name, k -> new ArrayList<>()).add(value);
+ }
+
+ @Override
+ public void setHeader(String name, String value) {
+ headers.set(name, value);
+ }
+
+ @Override
+ public void setHeader(String name, Date value) {
+ headers.set(name, DateFormatter.format(value));
+ }
+
+ @Override
+ public void setHeader(String name, List value) {
+ headers.put(name, value);
+ }
+
+ @Override
+ public void addCookie(HttpCookie cookie) {
+ if (cookies == null) {
+ cookies = new ArrayList<>();
+ }
+ cookies.add(cookie);
+ }
+
+ @Override
+ public String contentType() {
+ return getContentType0();
+ }
+
+ private String getContentType0() {
+ if (contentType == null) {
+ String value = headers.getFirst(HttpHeaderNames.CONTENT_TYPE.getName());
+ contentType = value == null ? StringUtils.EMPTY_STRING : value.trim();
+ }
+ return contentType.isEmpty() ? null : contentType;
+ }
+
+ @Override
+ public void setContentType(String contentType) {
+ this.contentType = contentType == null ? StringUtils.EMPTY_STRING : contentType.trim();
+ headers.set(HttpHeaderNames.CONTENT_TYPE.getName(), getContentType0());
+ }
+
+ @Override
+ public String mediaType() {
+ String contentType = getContentType0();
+ if (contentType == null) {
+ return null;
+ }
+ int pos = contentType.indexOf(';');
+ return pos == -1 ? contentType : contentType.substring(0, pos).trim();
+ }
+
+ @Override
+ public String charset() {
+ String charset = getCharset0();
+ return charset == null ? StandardCharsets.UTF_8.name() : charset;
+ }
+
+ private String getCharset0() {
+ String contentType = getContentType0();
+ if (contentType == null) {
+ return null;
+ }
+ int pos = contentType.lastIndexOf("charset=");
+ return pos == -1 ? null : contentType.substring(pos + 8);
+ }
+
+ @Override
+ public String locale() {
+ return headers.getFirst("content-Language");
+ }
+
+ @Override
+ public void setLocale(String locale) {
+ headers.set("content-Language", locale);
+ }
+
+ @Override
+ public OutputStream outputStream() {
+ if (outputStream == null) {
+ outputStream = new ByteArrayOutputStream(1024);
+ }
+ return null;
+ }
+
+ @Override
+ public void setOutputStream(OutputStream os) {
+ outputStream = os;
+ }
+
+ @Override
+ public Object body() {
+ return body;
+ }
+
+ @Override
+ public void setBody(Object body) {
+ this.body = body;
+ }
+
+ @Override
+ public void sendRedirect(String location) {
+ setStatus(302);
+ setHeader("location", location);
+ commit();
+ }
+
+ @Override
+ public void sendError(int status) {
+ setStatus(status);
+ commit();
+ }
+
+ @Override
+ public void sendError(int status, String message) {
+ setStatus(status);
+ setBody(message);
+ commit();
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return committed.get();
+ }
+
+ @Override
+ public void commit() {
+ if (committed.compareAndSet(false, true)) {
+ return;
+ }
+
+ if (cookies != null) {
+ headers.put("set-cookie", HttpUtils.encodeCookies(cookies));
+ }
+
+ throw new IllegalStateException("The response has been committed");
+ }
+
+ @Override
+ public void reset() {
+ headers.clear();
+ status = 0;
+ contentType = null;
+ cookies = null;
+ resetBuffer();
+ body = null;
+ committed.set(false);
+ }
+
+ @Override
+ public void resetBuffer() {
+ if (outputStream != null) {
+ if (outputStream instanceof ByteArrayOutputStream) {
+ ((ByteArrayOutputStream) outputStream).reset();
+ return;
+ }
+ throw new UnsupportedOperationException("the output stream is not supported to reset");
+ }
+ }
+
+ @Override
+ public int getStatus() {
+ return status;
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return headers;
+ }
+
+ @Override
+ public Object getBody() {
+ return body == null ? outputStream : body;
+ }
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java
new file mode 100644
index 000000000000..84f9e3a35d52
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12.message;
+
+import org.apache.dubbo.remoting.http12.HttpResult;
+
+import java.util.List;
+import java.util.Map;
+
+public class DefaultHttpResult implements HttpResult {
+
+ private int status;
+ private Map> headers;
+ private T body;
+
+ @Override
+ public int getStatus() {
+ return status;
+ }
+
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return headers;
+ }
+
+ public void setHeaders(Map> headers) {
+ this.headers = headers;
+ }
+
+ @Override
+ public T getBody() {
+ return body;
+ }
+
+ public void setBody(T body) {
+ this.body = body;
+ }
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageAdapterFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageAdapterFactory.java
new file mode 100644
index 000000000000..735b408aec38
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageAdapterFactory.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.dubbo.remoting.http12.message;
+
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.remoting.http12.HttpChannel;
+import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.remoting.http12.HttpResponse;
+
+@SPI(scope = ExtensionScope.FRAMEWORK)
+public interface HttpMessageAdapterFactory {
+
+ HR adapterRequest(REQUEST rawRequest, HttpChannel channel);
+
+ HttpResponse adapterResponse(HR request, REQUEST rawRequest, RESPONSE rawResponse);
+
+ default HttpResponse adapterResponse(HR request, REQUEST rawRequest) {
+ return adapterResponse(request, rawRequest, null);
+ }
+}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoder.java
index 94e247a57df8..9e27c15711c4 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoder.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoder.java
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.remoting.http12.message;
+import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.remoting.http12.exception.DecodeException;
import java.io.InputStream;
@@ -26,9 +27,7 @@ public interface HttpMessageDecoder extends CodecMediaType {
default Object[] decode(InputStream inputStream, Class>[] targetTypes) throws DecodeException {
// default decode first target type
- return new Object[] {
- this.decode(inputStream, targetTypes == null || targetTypes.length == 0 ? null : targetTypes[0])
- };
+ return new Object[] {decode(inputStream, ArrayUtils.isEmpty(targetTypes) ? null : targetTypes[0])};
}
MediaType mediaType();
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoder.java
index d4701ce5012f..e8a30f578387 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoder.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoder.java
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.remoting.http12.message;
+import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.remoting.http12.exception.EncodeException;
import java.io.OutputStream;
@@ -26,6 +27,6 @@ public interface HttpMessageEncoder extends CodecMediaType {
default void encode(OutputStream outputStream, Object[] data) throws EncodeException {
// default encode first data
- this.encode(outputStream, data == null || data.length == 0 ? null : data[0]);
+ encode(outputStream, ArrayUtils.isEmpty(data) ? null : data[0]);
}
}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java
index 601d82c57975..7150f2f17718 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java
@@ -17,132 +17,75 @@
package org.apache.dubbo.remoting.http12.message.codec;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.remoting.http12.HttpHeaders;
import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory;
import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;
import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory;
-import org.apache.dubbo.remoting.http12.message.MediaType;
import org.apache.dubbo.rpc.model.FrameworkModel;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
-import io.netty.handler.codec.CodecException;
+public final class CodecUtils {
-public class CodecUtils {
-
- private final FrameworkModel frameworkModel;
-
- private final List decoders;
-
- private final List encoders;
-
- private final Map encoderCache;
-
- private final Map decoderCache;
+ private final List decoderFactories;
+ private final List encoderFactories;
+ private final Map> encoderCache = new ConcurrentHashMap<>();
+ private final Map> decoderCache = new ConcurrentHashMap<>();
public CodecUtils(FrameworkModel frameworkModel) {
- this.encoderCache = new ConcurrentHashMap<>(1);
- this.decoderCache = new ConcurrentHashMap<>(1);
- this.frameworkModel = frameworkModel;
- this.decoders = frameworkModel
+ decoderFactories = frameworkModel
.getExtensionLoader(HttpMessageDecoderFactory.class)
.getActivateExtensions();
- this.encoders = frameworkModel
+ encoderFactories = frameworkModel
.getExtensionLoader(HttpMessageEncoderFactory.class)
.getActivateExtensions();
- decoders.forEach(
- decoderFactory -> decoderCache.put(decoderFactory.mediaType().getName(), decoderFactory));
- encoders.forEach(
- encoderFactory -> encoderCache.put(encoderFactory.mediaType().getName(), encoderFactory));
+ decoderFactories.forEach(factory -> decoderCache.put(factory.mediaType().getName(), Optional.of(factory)));
+ encoderFactories.forEach(factory -> encoderCache.put(factory.mediaType().getName(), Optional.of(factory)));
}
- public HttpMessageDecoder determineHttpMessageDecoder(FrameworkModel frameworkModel, String contentType, URL url) {
- return determineHttpMessageDecoderFactory(contentType).createCodec(url, frameworkModel, contentType);
+ public HttpMessageDecoder determineHttpMessageDecoder(URL url, FrameworkModel frameworkModel, String mediaType) {
+ return determineHttpMessageDecoderFactory(mediaType)
+ .orElseThrow(() -> new UnsupportedMediaTypeException(mediaType))
+ .createCodec(url, frameworkModel, mediaType);
}
- public HttpMessageEncoder determineHttpMessageEncoder(FrameworkModel frameworkModel, HttpHeaders headers, URL url) {
- String mediaType = getEncodeMediaType(headers);
- return determineHttpMessageEncoderFactory(mediaType).createCodec(url, frameworkModel, mediaType);
+ public HttpMessageEncoder determineHttpMessageEncoder(URL url, FrameworkModel frameworkModel, String mediaType) {
+ return determineHttpMessageEncoderFactory(mediaType)
+ .orElseThrow(() -> new UnsupportedMediaTypeException(mediaType))
+ .createCodec(url, frameworkModel, mediaType);
}
- public HttpMessageDecoderFactory determineHttpMessageDecoderFactory(String mediaType) {
- HttpMessageDecoderFactory factory = decoderCache.computeIfAbsent(mediaType, k -> {
- for (HttpMessageDecoderFactory decoderFactory : decoders) {
+ public Optional determineHttpMessageDecoderFactory(String mediaType) {
+ return decoderCache.computeIfAbsent(mediaType, k -> {
+ for (HttpMessageDecoderFactory decoderFactory : decoderFactories) {
if (decoderFactory.supports(mediaType)) {
- return decoderFactory;
+ return Optional.of(decoderFactory);
}
}
- return new UnsupportedCodecFactory();
+ return Optional.empty();
});
- if (factory instanceof UnsupportedCodecFactory) {
- throw new UnsupportedMediaTypeException(mediaType);
- }
- return factory;
}
- public HttpMessageEncoderFactory determineHttpMessageEncoderFactory(String mediaType) {
- HttpMessageEncoderFactory factory = encoderCache.computeIfAbsent(mediaType, k -> {
- for (HttpMessageEncoderFactory encoderFactory : encoders) {
+ public Optional determineHttpMessageEncoderFactory(String mediaType) {
+ return encoderCache.computeIfAbsent(mediaType, k -> {
+ for (HttpMessageEncoderFactory encoderFactory : encoderFactories) {
if (encoderFactory.supports(mediaType)) {
- return encoderFactory;
+ return Optional.of(encoderFactory);
}
}
- return new UnsupportedCodecFactory();
+ return Optional.empty();
});
- if (factory instanceof UnsupportedCodecFactory) {
- throw new UnsupportedMediaTypeException(mediaType);
- }
- return factory;
- }
-
- public List getDecoders() {
- return decoders;
- }
-
- public List getEncoders() {
- return encoders;
- }
-
- static class UnsupportedCodecFactory implements HttpMessageEncoderFactory, HttpMessageDecoderFactory {
- @Override
- public MediaType mediaType() {
- throw new CodecException();
- }
-
- @Override
- public boolean supports(String mediaType) {
- throw new CodecException();
- }
-
- @Override
- public HttpMessageCodec createCodec(URL url, FrameworkModel frameworkModel, String mediaType) {
- throw new CodecException();
- }
}
- public static String getEncodeMediaType(HttpHeaders headers) {
- String mediaType = headers.getAccept();
- if (mediaType == null) {
- mediaType = headers.getContentType();
- }
- return mediaType;
+ public List getDecoderFactories() {
+ return decoderFactories;
}
- public static ByteArrayOutputStream toByteArrayStream(InputStream in) throws IOException {
- ByteArrayOutputStream result = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024];
- int length;
- while ((length = in.read(buffer)) != -1) {
- result.write(buffer, 0, length);
- }
- return result;
+ public List getEncoderFactories() {
+ return encoderFactories;
}
}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodec.java
index da38387df0db..b787bf089bed 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodec.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodec.java
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.remoting.http12.message.codec;
+import org.apache.dubbo.common.io.StreamUtils;
import org.apache.dubbo.common.utils.JsonUtils;
import org.apache.dubbo.remoting.http12.exception.DecodeException;
import org.apache.dubbo.remoting.http12.exception.EncodeException;
@@ -67,13 +68,7 @@ public void encode(OutputStream outputStream, Object[] data) throws EncodeExcept
public Object decode(InputStream body, Class> targetType) throws DecodeException {
try {
try {
- int len;
- byte[] data = new byte[4096];
- StringBuilder builder = new StringBuilder(4096);
- while ((len = body.read(data)) != -1) {
- builder.append(new String(data, 0, len));
- }
- return JsonUtils.toJavaObject(builder.toString(), targetType);
+ return JsonUtils.toJavaObject(StreamUtils.toString(body), targetType);
} finally {
body.close();
}
@@ -87,14 +82,7 @@ public Object[] decode(InputStream dataInputStream, Class>[] targetTypes) thro
List result = new ArrayList<>();
try {
try {
- int len;
- byte[] data = new byte[4096];
- StringBuilder builder = new StringBuilder(4096);
- while ((len = dataInputStream.read(data)) != -1) {
- builder.append(new String(data, 0, len));
- }
- String jsonString = builder.toString();
- List jsonObjects = JsonUtils.toJavaList(jsonString, Object.class);
+ List jsonObjects = JsonUtils.toJavaList(StreamUtils.toString(dataInputStream), Object.class);
for (int i = 0; i < targetTypes.length; i++) {
Object jsonObject = jsonObjects.get(i);
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java
index caac2c3fb462..49b8788c4e82 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java
@@ -16,10 +16,10 @@
*/
package org.apache.dubbo.remoting.http12.message.codec;
+import org.apache.dubbo.common.io.StreamUtils;
import org.apache.dubbo.common.utils.MethodUtils;
import org.apache.dubbo.remoting.http12.exception.DecodeException;
import org.apache.dubbo.remoting.http12.exception.EncodeException;
-import org.apache.dubbo.remoting.http12.message.MediaType;
import java.io.IOException;
import java.io.InputStream;
@@ -31,11 +31,6 @@
public class JsonPbCodec extends JsonCodec {
- @Override
- public MediaType mediaType() {
- return MediaType.APPLICATION_JSON_VALUE;
- }
-
@Override
public void encode(OutputStream outputStream, Object unSerializedBody) throws EncodeException {
try {
@@ -59,15 +54,9 @@ public void encode(OutputStream outputStream, Object[] data) throws EncodeExcept
public Object decode(InputStream body, Class> targetType) throws DecodeException {
try {
if (isProtobuf(targetType)) {
- int len;
- byte[] data = new byte[4096];
- StringBuilder builder = new StringBuilder(4096);
- while ((len = body.read(data)) != -1) {
- builder.append(new String(data, 0, len));
- }
Message.Builder newBuilder = (Message.Builder)
MethodUtils.findMethod(targetType, "newBuilder").invoke(null);
- JsonFormat.parser().ignoringUnknownFields().merge(builder.toString(), newBuilder);
+ JsonFormat.parser().ignoringUnknownFields().merge(StreamUtils.toString(body), newBuilder);
return newBuilder.build();
}
} catch (Throwable e) {
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoder.java
index 560e5db1a786..4242bcd293fb 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoder.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoder.java
@@ -77,7 +77,7 @@ public Object[] decode(InputStream inputStream, Class>[] targetTypes) throws D
continue;
}
res[i] = codecUtils
- .determineHttpMessageDecoder(frameworkModel, part.headers.getContentType(), url)
+ .determineHttpMessageDecoder(url, frameworkModel, part.headers.getContentType())
.decode(new ByteArrayInputStream(part.content), targetTypes[i]);
}
return res;
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java
index 3516c749dc11..e07df957da8c 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.remoting.http12.message.codec;
+import org.apache.dubbo.common.io.StreamUtils;
import org.apache.dubbo.remoting.http12.exception.DecodeException;
import org.apache.dubbo.remoting.http12.exception.EncodeException;
import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
@@ -37,14 +38,14 @@ public PlainTextCodec(String contentType) {
@Override
public void encode(OutputStream outputStream, Object data) throws EncodeException {
- if (!(data instanceof String)) {
- throw new EncodeException("PlainText media-type only supports String as return type.");
- }
try {
- outputStream.write(((String) data).getBytes());
+ if (data instanceof String) {
+ outputStream.write(((String) data).getBytes(StandardCharsets.UTF_8));
+ }
} catch (IOException e) {
throw new EncodeException(e);
}
+ throw new EncodeException("PlainText media-type only supports String as return type.");
}
@Override
@@ -58,19 +59,16 @@ public Object decode(InputStream inputStream, Class> targetType) throws Decode
if (!String.class.equals(targetType)) {
throw new DecodeException("Plain text content only supports String as method param.");
}
- Charset charset;
- if (contentType.contains("charset=")) {
+ int pos = contentType.indexOf("charset=");
+ if (pos > 0) {
try {
- charset = Charset.forName(contentType.substring(contentType.indexOf("charset=") + 8));
+ Charset charset = Charset.forName(contentType.substring(pos + 8));
+ return StreamUtils.toString(inputStream, charset);
} catch (Exception e) {
throw new DecodeException("Unsupported charset:" + e.getMessage());
}
- if (!charset.equals(StandardCharsets.UTF_8) && !charset.equals(StandardCharsets.US_ASCII)) {
- String origin = CodecUtils.toByteArrayStream(inputStream).toString(charset.name());
- return new String(origin.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
- }
}
- return CodecUtils.toByteArrayStream(inputStream).toString(StandardCharsets.UTF_8.name());
+ return StreamUtils.toString(inputStream);
} catch (Exception e) {
throw new DecodeException(e);
}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodec.java
index 2e16b6d38282..cf390331a271 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodec.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodec.java
@@ -17,6 +17,7 @@
package org.apache.dubbo.remoting.http12.message.codec;
import org.apache.dubbo.common.convert.ConverterUtil;
+import org.apache.dubbo.common.io.StreamUtils;
import org.apache.dubbo.remoting.http12.exception.DecodeException;
import org.apache.dubbo.remoting.http12.exception.EncodeException;
import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
@@ -25,6 +26,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
+import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
@@ -48,11 +50,14 @@ public void encode(OutputStream outputStream, Object data) throws EncodeExceptio
for (Map.Entry, ?> e : ((Map, ?>) data).entrySet()) {
String k = e.getKey().toString();
String v = e.getValue().toString();
- toWrite.append(k).append("=").append(v).append("&");
+ toWrite.append(k)
+ .append("=")
+ .append(URLEncoder.encode(v, StandardCharsets.UTF_8.name()))
+ .append("&");
}
if (toWrite.length() > 1) {
outputStream.write(
- toWrite.substring(0, toWrite.length() - 1).getBytes());
+ toWrite.substring(0, toWrite.length() - 1).getBytes(StandardCharsets.UTF_8));
}
} else {
throw new EncodeException("UrlEncodeFrom media-type only supports String or Map as return type.");
@@ -84,8 +89,7 @@ else if (Arrays.stream(targetTypes)
throw new DecodeException(
"For x-www-form-urlencoded MIME type, please use Map/String/base-types as method param.");
}
- String decoded = URLDecoder.decode(
- CodecUtils.toByteArrayStream(inputStream).toString(), StandardCharsets.UTF_8.name())
+ String decoded = URLDecoder.decode(StreamUtils.toString(inputStream), StandardCharsets.UTF_8.name())
.trim();
Map res = toMap(decoded, targetTypes, toMap);
if (toMap) {
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodec.java
index 9d2bd8f02045..96ddfefc486e 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodec.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodec.java
@@ -30,7 +30,6 @@
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.StringReader;
import org.xml.sax.InputSource;
@@ -55,10 +54,7 @@ public Object decode(InputStream inputStream, Class> targetType) throws Decode
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
// Do unmarshall operation
- Source xmlSource = new SAXSource(
- spf.newSAXParser().getXMLReader(),
- new InputSource(new StringReader(
- CodecUtils.toByteArrayStream(inputStream).toString())));
+ Source xmlSource = new SAXSource(spf.newSAXParser().getXMLReader(), new InputSource(inputStream));
JAXBContext context = JAXBContext.newInstance(targetType);
Unmarshaller unmarshaller = context.createUnmarshaller();
return unmarshaller.unmarshal(xmlSource);
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1Channel.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1Channel.java
index c71cd1cee994..443bd21aec06 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1Channel.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1Channel.java
@@ -60,6 +60,11 @@ public SocketAddress remoteAddress() {
return channel.remoteAddress();
}
+ @Override
+ public SocketAddress localAddress() {
+ return channel.localAddress();
+ }
+
@Override
public void flush() {}
}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1ConnectionHandler.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1ConnectionHandler.java
index c43fa7cab600..20681d77e309 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1ConnectionHandler.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1ConnectionHandler.java
@@ -18,16 +18,9 @@
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.threadpool.ThreadPool;
-import org.apache.dubbo.common.utils.Assert;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.remoting.http12.HttpHeaderNames;
-import org.apache.dubbo.remoting.http12.HttpHeaders;
-import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException;
import org.apache.dubbo.remoting.http12.h1.Http1Request;
-import org.apache.dubbo.remoting.http12.h1.Http1ServerChannelObserver;
import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener;
import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListenerFactory;
-import org.apache.dubbo.remoting.http12.message.codec.CodecUtils;
import org.apache.dubbo.rpc.model.FrameworkModel;
import java.util.concurrent.Executor;
@@ -37,83 +30,36 @@
public class NettyHttp1ConnectionHandler extends SimpleChannelInboundHandler {
- private Http1ServerTransportListenerFactory http1ServerTransportListenerFactory;
+ private final URL url;
private final FrameworkModel frameworkModel;
- private final URL url;
+ private final Http1ServerTransportListenerFactory http1ServerTransportListenerFactory;
private final Executor executor;
- private final CodecUtils codecUtils;
-
- private Http1ServerChannelObserver errorResponseObserver;
-
- public NettyHttp1ConnectionHandler(URL url, FrameworkModel frameworkModel) {
- this.url = url;
- this.frameworkModel = frameworkModel;
- this.executor = url.getOrDefaultFrameworkModel()
- .getExtensionLoader(ThreadPool.class)
- .getAdaptiveExtension()
- .getExecutor(url);
- this.codecUtils = frameworkModel.getBeanFactory().getBean(CodecUtils.class);
- }
-
public NettyHttp1ConnectionHandler(
URL url,
FrameworkModel frameworkModel,
Http1ServerTransportListenerFactory http1ServerTransportListenerFactory) {
this.url = url;
this.frameworkModel = frameworkModel;
- this.executor = url.getOrDefaultFrameworkModel()
+ this.http1ServerTransportListenerFactory = http1ServerTransportListenerFactory;
+ executor = url.getOrDefaultFrameworkModel()
.getExtensionLoader(ThreadPool.class)
.getAdaptiveExtension()
.getExecutor(url);
- this.codecUtils = frameworkModel.getBeanFactory().getBean(CodecUtils.class);
- this.http1ServerTransportListenerFactory = http1ServerTransportListenerFactory;
- }
-
- public void setHttp1ServerTransportListenerFactory(
- Http1ServerTransportListenerFactory http1ServerTransportListenerFactory) {
- this.http1ServerTransportListenerFactory = http1ServerTransportListenerFactory;
}
+ /**
+ * process h1 request
+ */
protected void channelRead0(ChannelHandlerContext ctx, Http1Request http1Request) {
- // process h1 request
- Http1ServerTransportListener http1TransportListener = initTransportListenerIfNecessary(ctx, http1Request);
- initErrorResponseObserver(ctx, http1Request);
- executor.execute(() -> {
- try {
- http1TransportListener.onMetadata(http1Request);
- http1TransportListener.onData(http1Request);
- } catch (Exception e) {
- errorResponseObserver.onError(e);
- }
- });
- }
-
- private Http1ServerTransportListener initTransportListenerIfNecessary(
- ChannelHandlerContext ctx, Http1Request http1Request) {
- // each h1 request create http1TransportListener instance
- Http1ServerTransportListenerFactory http1ServerTransportListenerFactory =
- this.http1ServerTransportListenerFactory;
- Assert.notNull(http1ServerTransportListenerFactory, "http1ServerTransportListenerFactory must be not null.");
Http1ServerTransportListener http1TransportListener = http1ServerTransportListenerFactory.newInstance(
new NettyHttp1Channel(ctx.channel()), url, frameworkModel);
-
- HttpHeaders headers = http1Request.headers();
- String contentType = headers.getFirst(HttpHeaderNames.CONTENT_TYPE.getName());
- if (!StringUtils.hasText(contentType)) {
- throw new UnsupportedMediaTypeException(contentType);
- }
- // check ContentType
- codecUtils.determineHttpMessageDecoder(frameworkModel, headers.getContentType(), url);
- return http1TransportListener;
- }
-
- private void initErrorResponseObserver(ChannelHandlerContext ctx, Http1Request request) {
- this.errorResponseObserver = new Http1ServerChannelObserver(new NettyHttp1Channel(ctx.channel()));
- this.errorResponseObserver.setResponseEncoder(
- codecUtils.determineHttpMessageEncoder(frameworkModel, request.headers(), url));
+ executor.execute(() -> {
+ http1TransportListener.onMetadata(http1Request);
+ http1TransportListener.onData(http1Request);
+ });
}
}
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyH2StreamChannel.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyH2StreamChannel.java
index 05941658cfa8..f85b12763435 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyH2StreamChannel.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyH2StreamChannel.java
@@ -66,6 +66,11 @@ public SocketAddress remoteAddress() {
return this.http2StreamChannel.remoteAddress();
}
+ @Override
+ public SocketAddress localAddress() {
+ return this.http2StreamChannel.localAddress();
+ }
+
@Override
public void flush() {
this.http2StreamChannel.flush();
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2ProtocolSelectorHandler.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2ProtocolSelectorHandler.java
index f102a8732444..cc82019a7e4b 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2ProtocolSelectorHandler.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2ProtocolSelectorHandler.java
@@ -17,7 +17,6 @@
package org.apache.dubbo.remoting.http12.netty4.h2;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.remoting.http12.HttpHeaderNames;
import org.apache.dubbo.remoting.http12.HttpHeaders;
import org.apache.dubbo.remoting.http12.HttpMetadata;
@@ -38,16 +37,11 @@
public class NettyHttp2ProtocolSelectorHandler extends SimpleChannelInboundHandler {
- private Http2ServerTransportListenerFactory defaultHttp2ServerTransportListenerFactory;
-
private final URL url;
private final FrameworkModel frameworkModel;
- public NettyHttp2ProtocolSelectorHandler(URL url, FrameworkModel frameworkModel) {
- this.url = url;
- this.frameworkModel = frameworkModel;
- }
+ private final Http2ServerTransportListenerFactory defaultHttp2ServerTransportListenerFactory;
public NettyHttp2ProtocolSelectorHandler(
URL url,
@@ -62,11 +56,7 @@ public NettyHttp2ProtocolSelectorHandler(
protected void channelRead0(ChannelHandlerContext ctx, HttpMetadata metadata) {
HttpHeaders headers = metadata.headers();
String contentType = headers.getFirst(HttpHeaderNames.CONTENT_TYPE.getName());
- // 415
- if (!StringUtils.hasText(contentType)) {
- throw new UnsupportedMediaTypeException(contentType);
- }
- Http2ServerTransportListenerFactory factory = adaptHttp2ServerTransportListenerFactory(contentType);
+ Http2ServerTransportListenerFactory factory = determineHttp2ServerTransportListenerFactory(contentType);
if (factory == null) {
throw new UnsupportedMediaTypeException(contentType);
}
@@ -84,7 +74,7 @@ protected void channelRead0(ChannelHandlerContext ctx, HttpMetadata metadata) {
ctx.fireChannelRead(metadata);
}
- private Http2ServerTransportListenerFactory adaptHttp2ServerTransportListenerFactory(String contentType) {
+ private Http2ServerTransportListenerFactory determineHttp2ServerTransportListenerFactory(String contentType) {
Set http2ServerTransportListenerFactories = frameworkModel
.getExtensionLoader(Http2ServerTransportListenerFactory.class)
.getSupportedExtensionInstances();
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodeUtilsTest.java b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodeUtilsTest.java
index b8436c1c171f..7057f5f9cee5 100644
--- a/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodeUtilsTest.java
+++ b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodeUtilsTest.java
@@ -39,13 +39,14 @@ void testDetermineHttpCodec() {
HttpHeaderNames.CONTENT_TYPE.getName(),
Collections.singletonList(MediaType.APPLICATION_JSON_VALUE.getName()));
HttpMessageDecoder decoder =
- codecUtils.determineHttpMessageDecoder(FrameworkModel.defaultModel(), headers.getContentType(), null);
+ codecUtils.determineHttpMessageDecoder(null, FrameworkModel.defaultModel(), headers.getContentType());
Assertions.assertNotNull(decoder);
Assertions.assertEquals(JsonPbCodec.class, decoder.getClass());
HttpMessageEncoder encoder;
// If no Accept header provided, use Content-Type to find encoder
- encoder = codecUtils.determineHttpMessageEncoder(FrameworkModel.defaultModel(), headers, null);
+ encoder = codecUtils.determineHttpMessageEncoder(
+ null, FrameworkModel.defaultModel(), MediaType.APPLICATION_JSON_VALUE.getName());
Assertions.assertNotNull(encoder);
Assertions.assertEquals(JsonPbCodec.class, encoder.getClass());
@@ -54,17 +55,19 @@ void testDetermineHttpCodec() {
HttpHeaderNames.CONTENT_TYPE.getName(),
Collections.singletonList(MediaType.MULTIPART_FORM_DATA.getName()));
decoder =
- codecUtils.determineHttpMessageDecoder(FrameworkModel.defaultModel(), headers1.getContentType(), null);
+ codecUtils.determineHttpMessageDecoder(null, FrameworkModel.defaultModel(), headers1.getContentType());
Assertions.assertNotNull(decoder);
Assertions.assertEquals(MultipartDecoder.class, decoder.getClass());
Assertions.assertThrows(
UnsupportedMediaTypeException.class,
- () -> codecUtils.determineHttpMessageEncoder(FrameworkModel.defaultModel(), headers1, null));
+ () -> codecUtils.determineHttpMessageEncoder(
+ null, FrameworkModel.defaultModel(), MediaType.APPLICATION_JSON_VALUE.getName()));
headers1.put(
HttpHeaderNames.ACCEPT.getName(),
Collections.singletonList(MediaType.APPLICATION_JSON_VALUE.getName()));
- encoder = codecUtils.determineHttpMessageEncoder(FrameworkModel.defaultModel(), headers1, null);
+ encoder = codecUtils.determineHttpMessageEncoder(
+ null, FrameworkModel.defaultModel(), MediaType.APPLICATION_JSON_VALUE.getName());
Assertions.assertNotNull(encoder);
Assertions.assertEquals(JsonPbCodec.class, encoder.getClass());
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/pom.xml b/dubbo-rpc/dubbo-rpc-triple/pom.xml
index bbaa7edd6849..cc9cdd04ff42 100644
--- a/dubbo-rpc/dubbo-rpc-triple/pom.xml
+++ b/dubbo-rpc/dubbo-rpc-triple/pom.xml
@@ -55,6 +55,28 @@
com.google.protobuf
protobuf-java
+
+ org.springframework
+ spring-webmvc
+ 3.2.18.RELEASE
+ true
+
+
+ org.springframework
+ spring-web
+ 3.2.18.RELEASE
+ true
+
+
+ javax.servlet
+ javax.servlet-api
+ true
+
+
+ org.jboss.resteasy
+ resteasy-jaxrs
+ provided
+
org.springframework
spring-test
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/DescriptorUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/DescriptorUtils.java
new file mode 100644
index 000000000000..64f25fff4c5d
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/DescriptorUtils.java
@@ -0,0 +1,155 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.remoting.http12.exception.UnimplementedException;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.model.MethodDescriptor;
+import org.apache.dubbo.rpc.model.ProviderModel;
+import org.apache.dubbo.rpc.model.ServiceDescriptor;
+import org.apache.dubbo.rpc.protocol.tri.TripleCustomerProtocolWapper.TripleRequestWrapper;
+import org.apache.dubbo.rpc.service.ServiceDescriptorInternalCache;
+import org.apache.dubbo.rpc.stub.StubSuppliers;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * The MetaUtils provides utility methods for working with service descriptors and method descriptors.
+ */
+public final class DescriptorUtils {
+
+ private DescriptorUtils() {}
+
+ public static ServiceDescriptor findServiceDescriptor(Invoker> invoker, String serviceName, boolean hasStub)
+ throws UnimplementedException {
+ ServiceDescriptor result;
+ if (hasStub) {
+ result = getStubServiceDescriptor(invoker.getUrl(), serviceName);
+ } else {
+ result = getReflectionServiceDescriptor(invoker.getUrl());
+ }
+ if (result == null) {
+ throw new UnimplementedException("service:" + serviceName);
+ }
+ return result;
+ }
+
+ public static ServiceDescriptor getStubServiceDescriptor(URL url, String serviceName) {
+ ServiceDescriptor serviceDescriptor;
+ if (url.getServiceModel() != null) {
+ serviceDescriptor = url.getServiceModel().getServiceModel();
+ } else {
+ serviceDescriptor = StubSuppliers.getServiceDescriptor(serviceName);
+ }
+ return serviceDescriptor;
+ }
+
+ public static ServiceDescriptor getReflectionServiceDescriptor(URL url) {
+ ProviderModel providerModel = (ProviderModel) url.getServiceModel();
+ if (providerModel == null || providerModel.getServiceModel() == null) {
+ return null;
+ }
+ return providerModel.getServiceModel();
+ }
+
+ public static MethodDescriptor findMethodDescriptor(
+ ServiceDescriptor serviceDescriptor, String originalMethodName, boolean hasStub)
+ throws UnimplementedException {
+ MethodDescriptor result;
+ if (hasStub) {
+ result = serviceDescriptor.getMethods(originalMethodName).get(0);
+ } else {
+ result = findReflectionMethodDescriptor(serviceDescriptor, originalMethodName);
+ }
+ return result;
+ }
+
+ public static MethodDescriptor findReflectionMethodDescriptor(
+ ServiceDescriptor serviceDescriptor, String methodName) {
+ MethodDescriptor methodDescriptor = null;
+ if (isGeneric(methodName)) {
+ // There should be one and only one
+ methodDescriptor = ServiceDescriptorInternalCache.genericService()
+ .getMethods(methodName)
+ .get(0);
+ } else if (isEcho(methodName)) {
+ // There should be one and only one
+ return ServiceDescriptorInternalCache.echoService()
+ .getMethods(methodName)
+ .get(0);
+ } else {
+ List methodDescriptors = serviceDescriptor.getMethods(methodName);
+ // try lower-case method
+ if (CollectionUtils.isEmpty(methodDescriptors)) {
+ String lowerMethod = Character.toLowerCase(methodName.charAt(0)) + methodName.substring(1);
+ methodDescriptors = serviceDescriptor.getMethods(lowerMethod);
+ }
+ if (CollectionUtils.isEmpty(methodDescriptors)) {
+ return null;
+ }
+ // In most cases there is only one method
+ if (methodDescriptors.size() == 1) {
+ methodDescriptor = methodDescriptors.get(0);
+ }
+ // generated unary method ,use unary type
+ // Response foo(Request)
+ // void foo(Request,StreamObserver)
+ if (methodDescriptors.size() == 2) {
+ if (methodDescriptors.get(1).getRpcType() == MethodDescriptor.RpcType.SERVER_STREAM) {
+ methodDescriptor = methodDescriptors.get(0);
+ } else if (methodDescriptors.get(0).getRpcType() == MethodDescriptor.RpcType.SERVER_STREAM) {
+ methodDescriptor = methodDescriptors.get(1);
+ }
+ }
+ }
+ return methodDescriptor;
+ }
+
+ public static MethodDescriptor findTripleMethodDescriptor(
+ ServiceDescriptor serviceDescriptor, String methodName, byte[] data) {
+ MethodDescriptor methodDescriptor = findReflectionMethodDescriptor(serviceDescriptor, methodName);
+ if (methodDescriptor == null) {
+ List methodDescriptors = serviceDescriptor.getMethods(methodName);
+ TripleRequestWrapper request = TripleRequestWrapper.parseFrom(data);
+ String[] paramTypes = request.getArgTypes().toArray(new String[0]);
+ // wrapper mode the method can overload so maybe list
+ for (MethodDescriptor descriptor : methodDescriptors) {
+ // params type is array
+ if (Arrays.equals(descriptor.getCompatibleParamSignatures(), paramTypes)) {
+ methodDescriptor = descriptor;
+ break;
+ }
+ }
+ if (methodDescriptor == null) {
+ throw new UnimplementedException("method:" + methodName);
+ }
+ }
+ return methodDescriptor;
+ }
+
+ private static boolean isGeneric(String methodName) {
+ return CommonConstants.$INVOKE.equals(methodName) || CommonConstants.$INVOKE_ASYNC.equals(methodName);
+ }
+
+ private static boolean isEcho(String methodName) {
+ return CommonConstants.$ECHO.equals(methodName);
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestMetadata.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestMetadata.java
index 90477e7336ee..a015603d0635 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestMetadata.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestMetadata.java
@@ -55,7 +55,7 @@ public DefaultHttp2Headers toHeaders() {
.authority(address)
.method(HttpMethod.POST.asciiName())
.path("/" + service + "/" + method.getMethodName())
- .set(TripleHeaderEnum.CONTENT_TYPE_KEY.getHeader(), TripleConstant.CONTENT_PROTO)
+ .set(TripleHeaderEnum.CONTENT_TYPE_KEY.getHeader(), TripleConstant.CONTENT_TYPE_PROTO)
.set(HttpHeaderNames.TE, HttpHeaderValues.TRAILERS);
setIfNotNull(header, TripleHeaderEnum.TIMEOUT.getHeader(), timeout);
if (!ignoreDefaultVersion || !"1.0.0".equals(version)) {
@@ -67,7 +67,7 @@ public DefaultHttp2Headers toHeaders() {
if (!Identity.MESSAGE_ENCODING.equals(compressor.getMessageEncoding())) {
setIfNotNull(header, TripleHeaderEnum.GRPC_ENCODING.getHeader(), compressor.getMessageEncoding());
}
- StreamUtils.convertAttachment(header, attachments, convertNoLowerHeader);
+ StreamUtils.putHeaders(header, attachments, convertNoLowerHeader);
return header;
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleConstant.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleConstant.java
index 6ca934255fd7..56331e7f38e6 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleConstant.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleConstant.java
@@ -16,14 +16,16 @@
*/
package org.apache.dubbo.rpc.protocol.tri;
+import org.apache.dubbo.remoting.http12.message.MediaType;
+
import io.netty.util.AsciiString;
public class TripleConstant {
- public static final String CONTENT_PROTO = "application/grpc+proto";
- public static final String APPLICATION_GRPC = "application/grpc";
- public static final String TEXT_PLAIN_UTF8 = "text/plain; encoding=utf-8";
- public static final String TRI_VERSION = "3.0-TRI";
+ public static final String CONTENT_TYPE_PROTO = "application/grpc+proto";
+ public static final MediaType MEDIA_TYPE_GRPC = new MediaType("application", "grpc");
+
+ public static final String DEFAULT_VERSION = "1.0.0";
public static final String SERIALIZATION_KEY = "serialization";
public static final String TE_KEY = "te";
@@ -35,4 +37,13 @@ public class TripleConstant {
public static final AsciiString HTTPS_SCHEME = AsciiString.of("https");
public static final AsciiString HTTP_SCHEME = AsciiString.of("http");
+
+ public static final String REMOTE_ADDRESS_KEY = "tri.remote.address";
+ public static final String HANDLER_TYPE_KEY = "tri.handler.type";
+ public static final String HTTP_REQUEST_KEY = "tri.http.request";
+ public static final String HTTP_RESPONSE_KEY = "tri.http.response";
+
+ public static final String TRIPLE_HANDLER_TYPE_REST = "rest";
+ public static final String TRIPLE_HANDLER_TYPE_HTTP = "http";
+ public static final String TRIPLE_HANDLER_TYPE_GRPC = "grpc";
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHeaderEnum.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHeaderEnum.java
index db1018e2d575..66f942e8cdd9 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHeaderEnum.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHeaderEnum.java
@@ -41,6 +41,7 @@ public enum TripleHeaderEnum {
CONSUMER_APP_NAME_KEY("tri-consumer-appname"),
SERVICE_VERSION("tri-service-version"),
SERVICE_GROUP("tri-service-group"),
+ SERVICE_TIMEOUT("tri-service-timeout"),
TRI_HEADER_CONVERT("tri-header-convert"),
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java
index 1a82e343a3c7..ea088c9af195 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java
@@ -20,7 +20,6 @@
import org.apache.dubbo.common.config.Configuration;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.extension.Activate;
-import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.remoting.ChannelHandler;
import org.apache.dubbo.remoting.api.AbstractWireProtocol;
import org.apache.dubbo.remoting.api.pu.ChannelHandlerPretender;
@@ -32,7 +31,6 @@
import org.apache.dubbo.remoting.http12.netty4.h2.NettyHttp2FrameCodec;
import org.apache.dubbo.remoting.http12.netty4.h2.NettyHttp2ProtocolSelectorHandler;
import org.apache.dubbo.remoting.utils.UrlUtils;
-import org.apache.dubbo.rpc.HeaderFilter;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.apache.dubbo.rpc.model.ScopeModelAware;
import org.apache.dubbo.rpc.protocol.tri.h12.TripleProtocolDetector;
@@ -43,7 +41,6 @@
import org.apache.dubbo.rpc.protocol.tri.transport.TripleTailHandler;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import io.netty.channel.ChannelDuplexHandler;
@@ -60,7 +57,6 @@
import io.netty.handler.flush.FlushConsolidationHandler;
import io.netty.handler.logging.LogLevel;
-import static org.apache.dubbo.common.constants.CommonConstants.HEADER_FILTER_KEY;
import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_ENABLE_PUSH_KEY;
import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_HEADER_TABLE_SIZE_KEY;
import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_INITIAL_WINDOW_SIZE_KEY;
@@ -84,7 +80,6 @@ public class TripleHttp2Protocol extends AbstractWireProtocol implements ScopeMo
public static final Http2FrameLogger SERVER_LOGGER = new Http2FrameLogger(LogLevel.DEBUG, "H2_SERVER");
- private ExtensionLoader filtersLoader;
private FrameworkModel frameworkModel;
public TripleHttp2Protocol() {
@@ -94,7 +89,6 @@ public TripleHttp2Protocol() {
@Override
public void setFrameworkModel(FrameworkModel frameworkModel) {
this.frameworkModel = frameworkModel;
- this.filtersLoader = frameworkModel.getExtensionLoader(HeaderFilter.class);
}
@Override
@@ -158,12 +152,6 @@ private void configurerHttp1Handlers(URL url, List handlers) {
private void configurerHttp2Handlers(URL url, List handlers) {
Configuration config = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultApplicationModel());
- final List headFilters;
- if (filtersLoader != null) {
- headFilters = filtersLoader.getActivateExtension(url, HEADER_FILTER_KEY);
- } else {
- headFilters = Collections.emptyList();
- }
final Http2FrameCodec codec = TripleHttp2FrameCodecBuilder.forServer()
.customizeConnection((connection) -> connection
.remote()
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java
index 4754d2bf4160..3e0add6c5ff8 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java
@@ -289,7 +289,7 @@ RequestMetadata createRequest(MethodDescriptor methodDescriptor, Invocation invo
meta.packableMethod = (PackableMethod) methodDescriptor;
} else {
meta.packableMethod = packableMethodCache.computeIfAbsent(
- methodDescriptor, (md) -> packableMethodFactory.create(md, url, TripleConstant.CONTENT_PROTO));
+ methodDescriptor, (md) -> packableMethodFactory.create(md, url, TripleConstant.CONTENT_TYPE_PROTO));
}
meta.convertNoLowerHeader = TripleProtocol.CONVERT_NO_LOWER_HEADER;
meta.ignoreDefaultVersion = TripleProtocol.IGNORE_1_0_0_VERSION;
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
index f5d0223467d8..0aa566729aa7 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
@@ -34,6 +34,7 @@
import org.apache.dubbo.rpc.protocol.AbstractExporter;
import org.apache.dubbo.rpc.protocol.AbstractProtocol;
import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor;
+import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingRegistry;
import org.apache.dubbo.rpc.protocol.tri.service.TriBuiltinService;
import java.util.Objects;
@@ -55,7 +56,9 @@
public class TripleProtocol extends AbstractProtocol {
private static final Logger logger = LoggerFactory.getLogger(TripleProtocol.class);
+
private final PathResolver pathResolver;
+ private final RequestMappingRegistry requestMappingRegistry;
private final TriBuiltinService triBuiltinService;
private final String acceptEncodings;
@@ -70,9 +73,9 @@ public class TripleProtocol extends AbstractProtocol {
public TripleProtocol(FrameworkModel frameworkModel) {
this.frameworkModel = frameworkModel;
- this.triBuiltinService = new TriBuiltinService(frameworkModel);
- this.pathResolver =
- frameworkModel.getExtensionLoader(PathResolver.class).getDefaultExtension();
+ triBuiltinService = new TriBuiltinService(frameworkModel);
+ pathResolver = frameworkModel.getDefaultExtension(PathResolver.class);
+ requestMappingRegistry = frameworkModel.getDefaultExtension(RequestMappingRegistry.class);
CONVERT_NO_LOWER_HEADER = ConfigurationUtils.getEnvConfiguration(ApplicationModel.defaultModel())
.getBoolean(H2_SUPPORT_NO_LOWER_HEADER_KEY, true);
IGNORE_1_0_0_VERSION = ConfigurationUtils.getEnvConfiguration(ApplicationModel.defaultModel())
@@ -81,7 +84,7 @@ public TripleProtocol(FrameworkModel frameworkModel) {
.getBoolean(H2_RESOLVE_FALLBACK_TO_DEFAULT_KEY, true);
Set supported =
frameworkModel.getExtensionLoader(DeCompressor.class).getSupportedExtensions();
- this.acceptEncodings = String.join(",", supported);
+ acceptEncodings = String.join(",", supported);
}
@Override
@@ -93,11 +96,13 @@ public int getDefaultPort() {
public Exporter export(Invoker invoker) throws RpcException {
URL url = invoker.getUrl();
String key = serviceKey(url);
- final AbstractExporter exporter = new AbstractExporter(invoker) {
+ AbstractExporter exporter = new AbstractExporter(invoker) {
@Override
public void afterUnExport() {
pathResolver.remove(url.getServiceKey());
pathResolver.remove(url.getServiceModel().getServiceModel().getInterfaceName());
+ // unregister rest request mapping
+ requestMappingRegistry.unregister(invoker);
// set service status
if (triBuiltinService.enable()) {
triBuiltinService
@@ -133,14 +138,16 @@ public void afterUnExport() {
if (previous != null) {
logger.info("Already exists an invoker[" + previous.getUrl() + "] on path["
+ url.getServiceModel().getServiceModel().getInterfaceName()
- + "], dubbo will skip override with invoker["
- + url + "]");
+ + "], dubbo will skip override with invoker[" + url + "]");
} else {
logger.info("Add fallback triple invoker[" + url + "] to path["
+ url.getServiceModel().getServiceModel().getInterfaceName() + "] with invoker[" + url + "]");
}
}
+ // register rest request mapping
+ requestMappingRegistry.register(invoker);
+
// set service status
if (triBuiltinService.enable()) {
triBuiltinService
@@ -187,10 +194,11 @@ protected Invoker protocolBindingRefer(Class type, URL url) throws Rpc
@Override
public void destroy() {
if (logger.isInfoEnabled()) {
- logger.info("Destroying protocol [" + this.getClass().getSimpleName() + "] ...");
+ logger.info("Destroying protocol [" + getClass().getSimpleName() + "] ...");
}
PortUnificationExchanger.close();
pathResolver.destroy();
+ requestMappingRegistry.destroy();
super.destroy();
}
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/aot/TripleReflectionTypeDescriberRegistrar.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/aot/TripleReflectionTypeDescriberRegistrar.java
index 0ac720184b63..1f69b886097f 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/aot/TripleReflectionTypeDescriberRegistrar.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/aot/TripleReflectionTypeDescriberRegistrar.java
@@ -22,7 +22,6 @@
import org.apache.dubbo.rpc.protocol.tri.transport.TripleCommandOutBoundHandler;
import org.apache.dubbo.rpc.protocol.tri.transport.TripleGoAwayHandler;
import org.apache.dubbo.rpc.protocol.tri.transport.TripleHttp2ClientResponseHandler;
-import org.apache.dubbo.rpc.protocol.tri.transport.TripleHttp2FrameServerHandler;
import org.apache.dubbo.rpc.protocol.tri.transport.TripleServerConnectionHandler;
import org.apache.dubbo.rpc.protocol.tri.transport.TripleTailHandler;
@@ -35,7 +34,7 @@ public class TripleReflectionTypeDescriberRegistrar implements ReflectionTypeDes
@Override
public List getTypeDescribers() {
List typeDescribers = new ArrayList<>();
- typeDescribers.add(buildTypeDescriberWithPublicMethod(TripleHttp2FrameServerHandler.class));
+ // typeDescribers.add(buildTypeDescriberWithPublicMethod(TripleHttp2FrameServerHandler.class));
typeDescribers.add(buildTypeDescriberWithPublicMethod(TripleCommandOutBoundHandler.class));
typeDescribers.add(buildTypeDescriberWithPublicMethod(TripleTailHandler.class));
typeDescribers.add(buildTypeDescriberWithPublicMethod(TripleServerConnectionHandler.class));
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCall.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCall.java
deleted file mode 100644
index fb8f516367e7..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCall.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.constants.CommonConstants;
-import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.rpc.CancellationContext;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.TriRpcStatus;
-import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.model.MethodDescriptor;
-import org.apache.dubbo.rpc.model.PackableMethod;
-import org.apache.dubbo.rpc.model.ServiceDescriptor;
-import org.apache.dubbo.rpc.protocol.tri.ClassLoadUtil;
-import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
-import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
-import org.apache.dubbo.rpc.protocol.tri.compressor.Compressor;
-import org.apache.dubbo.rpc.protocol.tri.compressor.Identity;
-import org.apache.dubbo.rpc.protocol.tri.observer.ServerCallToObserverAdapter;
-import org.apache.dubbo.rpc.protocol.tri.stream.ServerStream;
-import org.apache.dubbo.rpc.protocol.tri.stream.StreamUtils;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-
-import io.netty.handler.codec.http.HttpHeaderNames;
-import io.netty.handler.codec.http.HttpResponseStatus;
-import io.netty.handler.codec.http2.DefaultHttp2Headers;
-import io.netty.util.concurrent.Future;
-
-import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_CREATE_STREAM_TRIPLE;
-import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_PARSE;
-import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_REQUEST;
-import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_SERIALIZE_TRIPLE;
-
-public abstract class AbstractServerCall implements ServerCall, ServerStream.Listener {
-
- public static final String REMOTE_ADDRESS_KEY = "tri.remote.address";
- private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(AbstractServerCall.class);
-
- public final Invoker> invoker;
- public final FrameworkModel frameworkModel;
- public final ServerStream stream;
- public final Executor executor;
- public final String methodName;
- public final String serviceName;
- public final ServiceDescriptor serviceDescriptor;
- private final String acceptEncoding;
- public boolean autoRequestN = true;
- public Long timeout;
- ServerCall.Listener listener;
- private Compressor compressor;
- private boolean headerSent;
- private boolean closed;
- CancellationContext cancellationContext;
- protected MethodDescriptor methodDescriptor;
- protected PackableMethod packableMethod;
- protected Map requestMetadata;
-
- private Integer exceptionCode = CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS;
-
- public Integer getExceptionCode() {
- return exceptionCode;
- }
-
- public void setExceptionCode(Integer exceptionCode) {
- this.exceptionCode = exceptionCode;
- }
-
- private boolean isNeedReturnException = false;
-
- public boolean isNeedReturnException() {
- return isNeedReturnException;
- }
-
- public void setNeedReturnException(boolean needReturnException) {
- isNeedReturnException = needReturnException;
- }
-
- AbstractServerCall(
- Invoker> invoker,
- ServerStream stream,
- FrameworkModel frameworkModel,
- ServiceDescriptor serviceDescriptor,
- String acceptEncoding,
- String serviceName,
- String methodName,
- Executor executor) {
- Objects.requireNonNull(serviceDescriptor, "No service descriptor found for " + invoker.getUrl());
- this.invoker = invoker;
- // is already serialized in the stream, so we don't need to serialize it again.
- this.executor = executor;
- this.frameworkModel = frameworkModel;
- this.serviceDescriptor = serviceDescriptor;
- this.serviceName = serviceName;
- this.methodName = methodName;
- this.stream = stream;
- this.acceptEncoding = acceptEncoding;
- }
-
- // stream listener start
- @Override
- public void onHeader(Map requestMetadata) {
- this.requestMetadata = requestMetadata;
- if (serviceDescriptor == null) {
- responseErr(TriRpcStatus.UNIMPLEMENTED.withDescription("Service not found:" + serviceName));
- return;
- }
- startCall();
- }
-
- protected void startCall() {
- RpcInvocation invocation = buildInvocation(methodDescriptor);
- listener = startInternalCall(invocation, methodDescriptor, invoker);
- }
-
- @Override
- public final void request(int numMessages) {
- stream.request(numMessages);
- }
-
- @Override
- public final void sendMessage(Object message) {
- if (closed) {
- throw new IllegalStateException("Stream has already canceled");
- }
- // is already in executor
- doSendMessage(message);
- }
-
- private void doSendMessage(Object message) {
- if (closed) {
- return;
- }
- if (!headerSent) {
- sendHeader();
- }
- final byte[] data;
- try {
- data = packableMethod.packResponse(message);
- } catch (Exception e) {
- close(
- TriRpcStatus.INTERNAL
- .withDescription("Serialize response failed")
- .withCause(e),
- null);
- LOGGER.error(
- PROTOCOL_FAILED_SERIALIZE_TRIPLE,
- "",
- "",
- String.format("Serialize triple response failed, service=%s method=%s", serviceName, methodName),
- e);
- return;
- }
- if (data == null) {
- close(TriRpcStatus.INTERNAL.withDescription("Missing response"), null);
- return;
- }
- Future> future;
- if (compressor != null) {
- int compressedFlag = Identity.MESSAGE_ENCODING.equals(compressor.getMessageEncoding()) ? 0 : 1;
- final byte[] compressed = compressor.compress(data);
- future = stream.sendMessage(compressed, compressedFlag);
- } else {
- future = stream.sendMessage(data, 0);
- }
- future.addListener(f -> {
- if (!f.isSuccess()) {
- cancelDual(TriRpcStatus.CANCELLED
- .withDescription("Send message failed")
- .withCause(f.cause()));
- }
- });
- }
-
- @Override
- public final void onComplete() {
- if (listener == null) {
- // It will enter here when there is an error in the header
- return;
- }
- // Both 'onError' and 'onComplete' are termination operators.
- // The stream will be closed when 'onError' was called, and 'onComplete' is not allowed to be called again.
- if (isClosed()) {
- return;
- }
- listener.onComplete();
- }
-
- @Override
- public final void onMessage(byte[] message, boolean isReturnTriException) {
- ClassLoader tccl = Thread.currentThread().getContextClassLoader();
- try {
- Object instance = parseSingleMessage(message);
- listener.onMessage(instance, message.length);
- } catch (Exception e) {
- final TriRpcStatus status =
- TriRpcStatus.UNKNOWN.withDescription("Server error").withCause(e);
- close(status, null);
- LOGGER.error(
- PROTOCOL_FAILED_REQUEST,
- "",
- "",
- "Process request failed. service=" + serviceName + " method=" + methodName,
- e);
- } finally {
- ClassLoadUtil.switchContextLoader(tccl);
- }
- }
-
- protected abstract Object parseSingleMessage(byte[] data) throws Exception;
-
- @Override
- public final void onCancelByRemote(TriRpcStatus status) {
- closed = true;
- if (listener == null) {
- return;
- }
- cancellationContext.cancel(status.cause);
- listener.onCancel(status);
- }
- // stream listener end
-
- public final boolean isClosed() {
- return closed;
- }
-
- /**
- * Build the RpcInvocation with metadata and execute headerFilter
- *
- * @return RpcInvocation
- */
- protected RpcInvocation buildInvocation(MethodDescriptor methodDescriptor) {
- final URL url = invoker.getUrl();
- RpcInvocation inv = new RpcInvocation(
- url.getServiceModel(),
- methodDescriptor.getMethodName(),
- serviceDescriptor.getInterfaceName(),
- url.getProtocolServiceKey(),
- methodDescriptor.getParameterClasses(),
- new Object[0]);
- inv.setTargetServiceUniqueName(url.getServiceKey());
- inv.setReturnTypes(methodDescriptor.getReturnTypes());
- inv.setObjectAttachments(StreamUtils.toAttachments(requestMetadata));
- inv.put(REMOTE_ADDRESS_KEY, stream.remoteAddress());
- // handle timeout
- String timeout = (String) requestMetadata.get(TripleHeaderEnum.TIMEOUT.getHeader());
- try {
- if (Objects.nonNull(timeout)) {
- this.timeout = parseTimeoutToMills(timeout);
- }
- } catch (Throwable t) {
- LOGGER.warn(
- PROTOCOL_FAILED_PARSE,
- "",
- "",
- String.format(
- "Failed to parse request timeout set from:%s, service=%s " + "method=%s",
- timeout, serviceDescriptor.getInterfaceName(), methodName));
- }
- if (null != requestMetadata.get(TripleHeaderEnum.CONSUMER_APP_NAME_KEY.getHeader())) {
- inv.put(
- TripleHeaderEnum.CONSUMER_APP_NAME_KEY,
- requestMetadata.get(TripleHeaderEnum.CONSUMER_APP_NAME_KEY.getHeader()));
- }
- return inv;
- }
-
- private void sendHeader() {
- if (closed) {
- return;
- }
- if (headerSent) {
- throw new IllegalStateException("Header has already sent");
- }
- headerSent = true;
- DefaultHttp2Headers headers = new DefaultHttp2Headers();
- headers.status(HttpResponseStatus.OK.codeAsText());
- headers.set(HttpHeaderNames.CONTENT_TYPE, TripleConstant.CONTENT_PROTO);
- if (acceptEncoding != null) {
- headers.set(HttpHeaderNames.ACCEPT_ENCODING, acceptEncoding);
- }
- if (compressor != null) {
- headers.set(TripleHeaderEnum.GRPC_ENCODING.getHeader(), compressor.getMessageEncoding());
- }
- if (!exceptionCode.equals(CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS)) {
- headers.set(TripleHeaderEnum.TRI_EXCEPTION_CODE.getHeader(), String.valueOf(exceptionCode));
- }
- // send header failed will reset stream and close request observer cause no more data will be sent
- stream.sendHeader(headers).addListener(f -> {
- if (!f.isSuccess()) {
- cancelDual(TriRpcStatus.INTERNAL.withCause(f.cause()));
- }
- });
- }
-
- private void cancelDual(TriRpcStatus status) {
- closed = true;
- listener.onCancel(status);
- cancellationContext.cancel(status.asException());
- }
-
- public void cancelByLocal(Throwable throwable) {
- if (closed) {
- return;
- }
- closed = true;
- cancellationContext.cancel(throwable);
- stream.cancelByLocal(TriRpcStatus.CANCELLED.withCause(throwable));
- }
-
- public void setCompression(String compression) {
- if (headerSent) {
- throw new IllegalStateException("Can not set compression after header sent");
- }
- this.compressor = Compressor.getCompressor(frameworkModel, compression);
- }
-
- public void disableAutoRequestN() {
- autoRequestN = false;
- }
-
- public boolean isAutoRequestN() {
- return autoRequestN;
- }
-
- public void close(TriRpcStatus status, Map attachments) {
- doClose(status, attachments);
- }
-
- private void doClose(TriRpcStatus status, Map attachments) {
- if (closed) {
- return;
- }
- closed = true;
- stream.complete(status, attachments, isNeedReturnException, exceptionCode);
- }
-
- protected Long parseTimeoutToMills(String timeoutVal) {
- if (StringUtils.isEmpty(timeoutVal) || StringUtils.isContains(timeoutVal, "null")) {
- return null;
- }
- long value = Long.parseLong(timeoutVal.substring(0, timeoutVal.length() - 1));
- char unit = timeoutVal.charAt(timeoutVal.length() - 1);
- switch (unit) {
- case 'n':
- return TimeUnit.NANOSECONDS.toMillis(value);
- case 'u':
- return TimeUnit.MICROSECONDS.toMillis(value);
- case 'm':
- return value;
- case 'S':
- return TimeUnit.SECONDS.toMillis(value);
- case 'M':
- return TimeUnit.MINUTES.toMillis(value);
- case 'H':
- return TimeUnit.HOURS.toMillis(value);
- default:
- // invalid timeout config
- return null;
- }
- }
-
- /**
- * Error in create stream, unsupported config or triple protocol error.
- *
- * @param status response status
- */
- protected void responseErr(TriRpcStatus status) {
- if (closed) {
- return;
- }
- closed = true;
- stream.complete(status, null, false, CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS);
- LOGGER.error(
- PROTOCOL_FAILED_REQUEST,
- "",
- "",
- "Triple request error: service=" + serviceName + " method" + methodName,
- status.asException());
- }
-
- protected ServerCall.Listener startInternalCall(
- RpcInvocation invocation, MethodDescriptor methodDescriptor, Invoker> invoker) {
- this.cancellationContext = RpcContext.getCancellationContext();
- ServerCallToObserverAdapter responseObserver =
- new ServerCallToObserverAdapter<>(this, cancellationContext);
- try {
- ServerCall.Listener listener;
- switch (methodDescriptor.getRpcType()) {
- case UNARY:
- listener = new UnaryServerCallListener(
- invocation, invoker, responseObserver, packableMethod.needWrapper());
- request(2);
- break;
- case SERVER_STREAM:
- listener = new ServerStreamServerCallListener(invocation, invoker, responseObserver);
- request(2);
- break;
- case BI_STREAM:
- case CLIENT_STREAM:
- listener = new BiStreamServerCallListener(invocation, invoker, responseObserver);
- request(1);
- break;
- default:
- throw new IllegalStateException("Can not reach here");
- }
- return listener;
- } catch (Exception e) {
- LOGGER.error(PROTOCOL_FAILED_CREATE_STREAM_TRIPLE, "", "", "Create triple stream failed", e);
- responseErr(TriRpcStatus.INTERNAL
- .withDescription("Create stream failed")
- .withCause(e));
- }
- return null;
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCallListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCallListener.java
deleted file mode 100644
index 7fa838d8d75b..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/AbstractServerCallListener.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.rpc.CancellationContext;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.TriRpcStatus;
-import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
-import org.apache.dubbo.rpc.protocol.tri.observer.ServerCallToObserverAdapter;
-
-import java.net.InetSocketAddress;
-
-import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;
-import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_TIMEOUT_SERVER;
-
-public abstract class AbstractServerCallListener implements AbstractServerCall.Listener {
-
- private static final ErrorTypeAwareLogger LOGGER =
- LoggerFactory.getErrorTypeAwareLogger(AbstractServerCallListener.class);
- public final CancellationContext cancellationContext;
- final RpcInvocation invocation;
- final Invoker> invoker;
- final ServerCallToObserverAdapter responseObserver;
-
- public AbstractServerCallListener(
- RpcInvocation invocation, Invoker> invoker, ServerCallToObserverAdapter responseObserver) {
- this.invocation = invocation;
- this.invoker = invoker;
- this.cancellationContext = responseObserver.cancellationContext;
- this.responseObserver = responseObserver;
- }
-
- public void invoke() {
- RpcContext.restoreCancellationContext(cancellationContext);
- InetSocketAddress remoteAddress =
- (InetSocketAddress) invocation.getAttributes().remove(AbstractServerCall.REMOTE_ADDRESS_KEY);
- RpcContext.getServiceContext().setRemoteAddress(remoteAddress);
- String remoteApp = (String) invocation.getAttributes().remove(TripleHeaderEnum.CONSUMER_APP_NAME_KEY);
- if (null != remoteApp) {
- RpcContext.getServiceContext().setRemoteApplicationName(remoteApp);
- invocation.setAttachmentIfAbsent(REMOTE_APPLICATION_KEY, remoteApp);
- }
- final long stInMillis = System.currentTimeMillis();
- try {
- final Result response = invoker.invoke(invocation);
- response.whenCompleteWithContext((r, t) -> {
- responseObserver.setResponseAttachments(response.getObjectAttachments());
- if (t != null) {
- responseObserver.onError(t);
- return;
- }
- if (response.hasException()) {
- doOnResponseHasException(response.getException());
- return;
- }
- final long cost = System.currentTimeMillis() - stInMillis;
- if (responseObserver.isTimeout(cost)) {
- LOGGER.error(
- PROTOCOL_TIMEOUT_SERVER,
- "",
- "",
- String.format(
- "Invoke timeout at server side, ignored to send response. service=%s method=%s cost=%s",
- invocation.getTargetServiceUniqueName(), invocation.getMethodName(), cost));
- responseObserver.onCompleted(TriRpcStatus.DEADLINE_EXCEEDED);
- return;
- }
- onReturn(r.getValue());
- });
- } catch (Exception e) {
- responseObserver.onError(e);
- } finally {
- RpcContext.removeCancellationContext();
- RpcContext.removeContext();
- }
- }
-
- protected void doOnResponseHasException(Throwable t) {
- responseObserver.onError(t);
- }
-
- public abstract void onReturn(Object value);
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/BiStreamServerCallListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/BiStreamServerCallListener.java
deleted file mode 100644
index e37ac9d006ce..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/BiStreamServerCallListener.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.common.stream.StreamObserver;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.TriRpcStatus;
-import org.apache.dubbo.rpc.protocol.tri.observer.ServerCallToObserverAdapter;
-
-public class BiStreamServerCallListener extends AbstractServerCallListener {
-
- private StreamObserver requestObserver;
-
- public BiStreamServerCallListener(
- RpcInvocation invocation, Invoker> invoker, ServerCallToObserverAdapter responseObserver) {
- super(invocation, invoker, responseObserver);
- invocation.setArguments(new Object[] {responseObserver});
- invoke();
- }
-
- @Override
- public void onReturn(Object value) {
- this.requestObserver = (StreamObserver) value;
- }
-
- @Override
- public void onMessage(Object message, int actualContentLength) {
- if (message instanceof Object[]) {
- message = ((Object[]) message)[0];
- }
- requestObserver.onNext(message);
- if (responseObserver.isAutoRequestN()) {
- responseObserver.request(1);
- }
- }
-
- @Override
- public void onCancel(TriRpcStatus status) {
- requestObserver.onError(status.asException());
- }
-
- @Override
- public void onComplete() {
- requestObserver.onCompleted();
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ReflectionAbstractServerCall.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ReflectionAbstractServerCall.java
deleted file mode 100644
index 4be61a00df8a..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ReflectionAbstractServerCall.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.config.ConfigurationUtils;
-import org.apache.dubbo.common.constants.CommonConstants;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.rpc.HeaderFilter;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.TriRpcStatus;
-import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.model.MethodDescriptor;
-import org.apache.dubbo.rpc.model.MethodDescriptor.RpcType;
-import org.apache.dubbo.rpc.model.PackableMethod;
-import org.apache.dubbo.rpc.model.PackableMethodFactory;
-import org.apache.dubbo.rpc.model.ProviderModel;
-import org.apache.dubbo.rpc.model.ServiceDescriptor;
-import org.apache.dubbo.rpc.protocol.tri.ClassLoadUtil;
-import org.apache.dubbo.rpc.protocol.tri.TripleCustomerProtocolWapper;
-import org.apache.dubbo.rpc.protocol.tri.stream.ServerStream;
-import org.apache.dubbo.rpc.service.ServiceDescriptorInternalCache;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executor;
-
-import io.netty.handler.codec.http.HttpHeaderNames;
-
-import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PACKABLE_METHOD_FACTORY;
-
-public class ReflectionAbstractServerCall extends AbstractServerCall {
-
- private static final String PACKABLE_METHOD_CACHE = "PACKABLE_METHOD_CACHE";
- private final List headerFilters;
- private List methodDescriptors;
-
- public ReflectionAbstractServerCall(
- Invoker> invoker,
- ServerStream serverStream,
- FrameworkModel frameworkModel,
- String acceptEncoding,
- String serviceName,
- String methodName,
- List headerFilters,
- Executor executor) {
- super(
- invoker,
- serverStream,
- frameworkModel,
- getServiceDescriptor(invoker.getUrl()),
- acceptEncoding,
- serviceName,
- methodName,
- executor);
- this.headerFilters = headerFilters;
- }
-
- private static ServiceDescriptor getServiceDescriptor(URL url) {
- ProviderModel providerModel = (ProviderModel) url.getServiceModel();
- if (providerModel == null || providerModel.getServiceModel() == null) {
- return null;
- }
- return providerModel.getServiceModel();
- }
-
- private boolean isEcho(String methodName) {
- return CommonConstants.$ECHO.equals(methodName);
- }
-
- private boolean isGeneric(String methodName) {
- return CommonConstants.$INVOKE.equals(methodName) || CommonConstants.$INVOKE_ASYNC.equals(methodName);
- }
-
- @Override
- public void startCall() {
- if (isGeneric(methodName)) {
- // There should be one and only one
- methodDescriptor = ServiceDescriptorInternalCache.genericService()
- .getMethods(methodName)
- .get(0);
- } else if (isEcho(methodName)) {
- // There should be one and only one
- methodDescriptor = ServiceDescriptorInternalCache.echoService()
- .getMethods(methodName)
- .get(0);
- } else {
- methodDescriptors = serviceDescriptor.getMethods(methodName);
- // try lower-case method
- if (CollectionUtils.isEmpty(methodDescriptors)) {
- final String lowerMethod = Character.toLowerCase(methodName.charAt(0)) + methodName.substring(1);
- methodDescriptors = serviceDescriptor.getMethods(lowerMethod);
- }
- if (CollectionUtils.isEmpty(methodDescriptors)) {
- responseErr(TriRpcStatus.UNIMPLEMENTED.withDescription(
- "Method : " + methodName + " not found of service:" + serviceName));
- return;
- }
- // In most cases there is only one method
- if (methodDescriptors.size() == 1) {
- methodDescriptor = methodDescriptors.get(0);
- }
- // generated unary method ,use unary type
- // Response foo(Request)
- // void foo(Request,StreamObserver)
- if (methodDescriptors.size() == 2) {
- if (methodDescriptors.get(1).getRpcType() == RpcType.SERVER_STREAM) {
- methodDescriptor = methodDescriptors.get(0);
- } else if (methodDescriptors.get(0).getRpcType() == RpcType.SERVER_STREAM) {
- methodDescriptor = methodDescriptors.get(1);
- }
- }
- }
- if (methodDescriptor != null) {
- loadPackableMethod(invoker.getUrl());
- }
- trySetListener();
- if (listener == null) {
- // wrap request , need one message
- request(1);
- }
- }
-
- private void trySetListener() {
- if (listener != null) {
- return;
- }
- if (methodDescriptor == null) {
- return;
- }
- if (isClosed()) {
- return;
- }
- RpcInvocation invocation = buildInvocation(methodDescriptor);
- if (isClosed()) {
- return;
- }
- headerFilters.forEach(f -> f.invoke(invoker, invocation));
- if (isClosed()) {
- return;
- }
- listener = ReflectionAbstractServerCall.this.startInternalCall(invocation, methodDescriptor, invoker);
- }
-
- @Override
- protected Object parseSingleMessage(byte[] data) throws Exception {
- trySetMethodDescriptor(data);
- trySetListener();
- if (isClosed()) {
- return null;
- }
- ClassLoadUtil.switchContextLoader(invoker.getUrl().getServiceModel().getClassLoader());
- return packableMethod.getRequestUnpack().unpack(data);
- }
-
- private void trySetMethodDescriptor(byte[] data) {
- if (methodDescriptor != null) {
- return;
- }
- final TripleCustomerProtocolWapper.TripleRequestWrapper request;
- request = TripleCustomerProtocolWapper.TripleRequestWrapper.parseFrom(data);
-
- final String[] paramTypes =
- request.getArgTypes().toArray(new String[request.getArgs().size()]);
- // wrapper mode the method can overload so maybe list
- for (MethodDescriptor descriptor : methodDescriptors) {
- // params type is array
- if (Arrays.equals(descriptor.getCompatibleParamSignatures(), paramTypes)) {
- methodDescriptor = descriptor;
- break;
- }
- }
- if (methodDescriptor == null) {
- ReflectionAbstractServerCall.this.close(
- TriRpcStatus.UNIMPLEMENTED.withDescription(
- "Method :" + methodName + "[" + Arrays.toString(paramTypes) + "] " + "not found of service:"
- + serviceDescriptor.getInterfaceName()),
- null);
- return;
- }
- loadPackableMethod(invoker.getUrl());
- }
-
- @SuppressWarnings("unchecked")
- private void loadPackableMethod(URL url) {
- Map cacheMap = (Map) url.getServiceModel()
- .getServiceMetadata()
- .getAttributeMap()
- .computeIfAbsent(PACKABLE_METHOD_CACHE, (k) -> new ConcurrentHashMap<>());
- packableMethod = cacheMap.computeIfAbsent(methodDescriptor, (md) -> frameworkModel
- .getExtensionLoader(PackableMethodFactory.class)
- .getExtension(ConfigurationUtils.getGlobalConfiguration(url.getApplicationModel())
- .getString(DUBBO_PACKABLE_METHOD_FACTORY, DEFAULT_KEY))
- .create(methodDescriptor, url, (String) requestMetadata.get(HttpHeaderNames.CONTENT_TYPE.toString())));
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ServerCall.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ServerCall.java
deleted file mode 100644
index e5bdb365139c..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ServerCall.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.rpc.TriRpcStatus;
-
-import java.util.Map;
-
-/**
- * ServerCall manipulates server details of a RPC call. Request messages are acquired by {@link
- * Listener}. Backpressure is supported by {@link #request(int)}.Response messages are sent by
- * {@link ServerCall#sendMessage(Object)}.
- */
-public interface ServerCall {
-
- /**
- * A listener to receive request messages.
- */
- interface Listener {
-
- /**
- * Callback when a request message is received.
- *
- * @param message message received
- * @param actualContentLength actual content length from body
- */
- void onMessage(Object message, int actualContentLength);
-
- /**
- * @param status when the call is canceled.
- */
- void onCancel(TriRpcStatus status);
-
- /**
- * Request completed.
- */
- void onComplete();
- }
-
- /**
- * Send message to client
- *
- * @param message message to send
- */
- void sendMessage(Object message);
-
- /**
- * Request more request data from the client.
- *
- * @param numMessages max number of messages
- */
- void request(int numMessages);
-
- /**
- * Close the call.
- *
- * @param status status of the call to send to the client
- * @param responseAttrs response attachments
- */
- void close(TriRpcStatus status, Map responseAttrs);
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ServerStreamServerCallListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ServerStreamServerCallListener.java
deleted file mode 100644
index 8e5ea19caf15..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/ServerStreamServerCallListener.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.TriRpcStatus;
-import org.apache.dubbo.rpc.protocol.tri.observer.ServerCallToObserverAdapter;
-
-public class ServerStreamServerCallListener extends AbstractServerCallListener {
-
- public ServerStreamServerCallListener(
- RpcInvocation invocation, Invoker> invoker, ServerCallToObserverAdapter responseObserver) {
- super(invocation, invoker, responseObserver);
- }
-
- @Override
- public void onReturn(Object value) {}
-
- @Override
- public void onMessage(Object message, int actualContentLength) {
- if (message instanceof Object[]) {
- message = ((Object[]) message)[0];
- }
- invocation.setArguments(new Object[] {message, responseObserver});
- }
-
- @Override
- public void onCancel(TriRpcStatus status) {
- responseObserver.onError(status.asException());
- }
-
- @Override
- public void onComplete() {
- invoke();
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/StubAbstractServerCall.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/StubAbstractServerCall.java
deleted file mode 100644
index 139c42c415a8..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/StubAbstractServerCall.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.model.ServiceDescriptor;
-import org.apache.dubbo.rpc.model.StubMethodDescriptor;
-import org.apache.dubbo.rpc.protocol.tri.stream.ServerStream;
-import org.apache.dubbo.rpc.stub.StubSuppliers;
-
-import java.util.concurrent.Executor;
-
-public class StubAbstractServerCall extends AbstractServerCall {
-
- public StubAbstractServerCall(
- Invoker> invoker,
- ServerStream serverStream,
- FrameworkModel frameworkModel,
- String acceptEncoding,
- String serviceName,
- String methodName,
- Executor executor) {
- super(
- invoker,
- serverStream,
- frameworkModel,
- getServiceDescriptor(invoker.getUrl(), serviceName),
- acceptEncoding,
- serviceName,
- methodName,
- executor);
- this.methodDescriptor = serviceDescriptor.getMethods(methodName).get(0);
- this.packableMethod = (StubMethodDescriptor) methodDescriptor;
- }
-
- private static ServiceDescriptor getServiceDescriptor(URL url, String serviceName) {
- ServiceDescriptor serviceDescriptor;
- if (url.getServiceModel() != null) {
- serviceDescriptor = url.getServiceModel().getServiceModel();
- } else {
- serviceDescriptor = StubSuppliers.getServiceDescriptor(serviceName);
- }
- return serviceDescriptor;
- }
-
- @Override
- protected Object parseSingleMessage(byte[] data) throws Exception {
- return packableMethod.parseRequest(data);
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/UnaryServerCallListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/UnaryServerCallListener.java
deleted file mode 100644
index 9e6da9158f2b..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/UnaryServerCallListener.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.remoting.Constants;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.TriRpcStatus;
-import org.apache.dubbo.rpc.protocol.tri.observer.ServerCallToObserverAdapter;
-
-public class UnaryServerCallListener extends AbstractServerCallListener {
-
- private final boolean needWrapper;
-
- public UnaryServerCallListener(
- RpcInvocation invocation,
- Invoker> invoker,
- ServerCallToObserverAdapter responseObserver,
- boolean needWrapper) {
- super(invocation, invoker, responseObserver);
- this.needWrapper = needWrapper;
- }
-
- @Override
- public void onReturn(Object value) {
- responseObserver.onNext(value);
- responseObserver.onCompleted();
- }
-
- @Override
- public void onMessage(Object message, int actualContentLength) {
- if (message instanceof Object[]) {
- invocation.setArguments((Object[]) message);
- } else {
- invocation.setArguments(new Object[] {message});
- }
- invocation.put(Constants.CONTENT_LENGTH_KEY, actualContentLength);
- }
-
- @Override
- public void onCancel(TriRpcStatus status) {
- // ignored
- }
-
- @Override
- protected void doOnResponseHasException(Throwable t) {
- if (needWrapper) {
- onReturnException((Exception) t);
- } else {
- super.doOnResponseHasException(t);
- }
- }
-
- private void onReturnException(Exception value) {
- TriRpcStatus status = TriRpcStatus.getStatus(value);
- int exceptionCode = status.code.code;
- if (exceptionCode == TriRpcStatus.UNKNOWN.code.code) {
- exceptionCode = RpcException.BIZ_EXCEPTION;
- }
- responseObserver.setExceptionCode(exceptionCode);
- responseObserver.setNeedReturnException(true);
- onReturn(value);
- }
-
- @Override
- public void onComplete() {
- invoke();
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java
index 689d9d03e39f..1f4f984e9ecf 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java
@@ -25,8 +25,8 @@
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
-import org.apache.dubbo.rpc.protocol.tri.call.AbstractServerCall;
import java.net.InetSocketAddress;
@@ -57,7 +57,7 @@ public void invoke() {
((Http2CancelableStreamObserver) responseObserver).getCancellationContext());
}
InetSocketAddress remoteAddress =
- (InetSocketAddress) invocation.getAttributes().remove(AbstractServerCall.REMOTE_ADDRESS_KEY);
+ (InetSocketAddress) invocation.getAttributes().remove(TripleConstant.REMOTE_ADDRESS_KEY);
RpcContext.getServiceContext().setRemoteAddress(remoteAddress);
String remoteApp = (String) invocation.getAttributes().remove(TripleHeaderEnum.CONSUMER_APP_NAME_KEY);
if (null != remoteApp) {
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
index 1b8d5090888a..0e7fc25b38a8 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
@@ -20,50 +20,29 @@
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.common.utils.JsonUtils;
import org.apache.dubbo.remoting.http12.HttpChannel;
-import org.apache.dubbo.remoting.http12.HttpHeaderNames;
-import org.apache.dubbo.remoting.http12.HttpHeaders;
import org.apache.dubbo.remoting.http12.HttpInputMessage;
-import org.apache.dubbo.remoting.http12.HttpMetadata;
import org.apache.dubbo.remoting.http12.HttpStatus;
import org.apache.dubbo.remoting.http12.HttpTransportListener;
import org.apache.dubbo.remoting.http12.RequestMetadata;
import org.apache.dubbo.remoting.http12.exception.HttpStatusException;
-import org.apache.dubbo.remoting.http12.exception.IllegalPathException;
-import org.apache.dubbo.remoting.http12.exception.UnimplementedException;
-import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException;
-import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
import org.apache.dubbo.remoting.http12.message.MethodMetadata;
-import org.apache.dubbo.remoting.http12.message.codec.CodecUtils;
import org.apache.dubbo.rpc.HeaderFilter;
import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.PathResolver;
import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.TriRpcStatus;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.apache.dubbo.rpc.model.MethodDescriptor;
-import org.apache.dubbo.rpc.model.ProviderModel;
-import org.apache.dubbo.rpc.model.ServiceDescriptor;
+import org.apache.dubbo.rpc.protocol.tri.DescriptorUtils;
import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
-import org.apache.dubbo.rpc.protocol.tri.TripleProtocol;
+import org.apache.dubbo.rpc.protocol.tri.route.RequestRouter;
+import org.apache.dubbo.rpc.protocol.tri.route.RpcInvocationBuildContext;
import org.apache.dubbo.rpc.protocol.tri.stream.StreamUtils;
-import org.apache.dubbo.rpc.service.ServiceDescriptorInternalCache;
-import org.apache.dubbo.rpc.stub.StubSuppliers;
-import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import java.util.Optional;
import java.util.concurrent.Executor;
-import java.util.function.Supplier;
-import static org.apache.dubbo.common.constants.CommonConstants.HEADER_FILTER_KEY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ERROR_USE_THREAD_POOL;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_PARSE;
@@ -74,65 +53,37 @@ public abstract class AbstractServerTransportListener headerFilters;
- private HttpMessageDecoder httpMessageDecoder;
-
- private Invoker> invoker;
-
- private ServiceDescriptor serviceDescriptor;
-
- private MethodDescriptor methodDescriptor;
-
- private RpcInvocation rpcInvocation;
-
- private MethodMetadata methodMetadata;
-
- private HEADER httpMetadata;
-
private Executor executor;
-
- private boolean hasStub;
-
+ private HEADER httpMetadata;
+ private RpcInvocationBuildContext context;
private HttpMessageListener httpMessageListener;
- protected CodecUtils codecUtils;
-
public AbstractServerTransportListener(FrameworkModel frameworkModel, URL url, HttpChannel httpChannel) {
this.frameworkModel = frameworkModel;
this.url = url;
this.httpChannel = httpChannel;
- this.pathResolver =
- frameworkModel.getExtensionLoader(PathResolver.class).getDefaultExtension();
- this.headerFilters =
- frameworkModel.getExtensionLoader(HeaderFilter.class).getActivateExtension(url, HEADER_FILTER_KEY);
- this.codecUtils = frameworkModel.getBeanFactory().getOrRegisterBean(CodecUtils.class);
- }
-
- protected Executor initializeExecutor(HEADER metadata) {
- // default direct executor
- return Runnable::run;
+ requestRouter = frameworkModel.getDefaultExtension(RequestRouter.class);
+ headerFilters = frameworkModel
+ .getExtensionLoader(HeaderFilter.class)
+ .getActivateExtension(url, CommonConstants.HEADER_FILTER_KEY);
}
@Override
public void onMetadata(HEADER metadata) {
-
try {
- this.executor = initializeExecutor(metadata);
+ executor = initializeExecutor(metadata);
} catch (Throwable throwable) {
LOGGER.error(COMMON_ERROR_USE_THREAD_POOL, "", "", "initialize executor fail.", throwable);
onError(throwable);
return;
}
- if (this.executor == null) {
+ if (executor == null) {
LOGGER.error(INTERNAL_ERROR, "", "", "executor must be not null.");
onError(new NullPointerException("initializeExecutor return null"));
return;
@@ -147,41 +98,29 @@ public void onMetadata(HEADER metadata) {
});
}
+ protected Executor initializeExecutor(HEADER metadata) {
+ // default direct executor
+ return Runnable::run;
+ }
+
protected void doOnMetadata(HEADER metadata) {
onPrepareMetadata(metadata);
- this.httpMetadata = metadata;
- String path = metadata.path();
- HttpHeaders headers = metadata.headers();
- // 1.check necessary header
- String contentType = headers.getFirst(HttpHeaderNames.CONTENT_TYPE.getName());
- if (contentType == null) {
- throw new UnsupportedMediaTypeException(
- "'" + HttpHeaderNames.CONTENT_TYPE.getName() + "' must be not null.");
- }
+ httpMetadata = metadata;
- // 2. check service
- String[] parts = path.split("/");
- if (parts.length != 3) {
- throw new IllegalPathException(path);
- }
- String serviceName = parts[1];
- this.hasStub = pathResolver.hasNativeStub(path);
- this.invoker = getInvoker(metadata, serviceName);
- if (invoker == null) {
- throw new UnimplementedException(serviceName);
+ context = requestRouter.route(url, metadata, httpChannel);
+ if (context == null) {
+ throw new HttpStatusException(404, "Invoker not found");
}
- this.httpMessageDecoder =
- codecUtils.determineHttpMessageDecoder(getFrameworkModel(), headers.getContentType(), getUrl());
- setServiceDescriptor(findServiceDescriptor(invoker, serviceName, hasStub));
- setHttpMessageListener(newHttpMessageListener());
+
+ setHttpMessageListener(buildHttpMessageListener());
onMetadataCompletion(metadata);
}
- protected abstract HttpMessageListener newHttpMessageListener();
+ protected abstract HttpMessageListener buildHttpMessageListener();
@Override
public void onData(MESSAGE message) {
- this.executor.execute(() -> {
+ executor.execute(() -> {
try {
doOnData(message);
} catch (Throwable e) {
@@ -192,10 +131,9 @@ public void onData(MESSAGE message) {
}
protected void doOnData(MESSAGE message) {
- // decode message
onPrepareData(message);
- InputStream body = message.getBody();
- httpMessageListener.onMessage(body);
+ // decode message
+ httpMessageListener.onMessage(message.getBody());
onDataCompletion(message);
}
@@ -231,266 +169,76 @@ protected void onError(Throwable throwable) {
throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), throwable);
}
- private Invoker> getInvoker(HEADER metadata, String serviceName) {
- HttpHeaders headers = metadata.headers();
- final String version = headers.containsKey(TripleHeaderEnum.SERVICE_VERSION.getHeader())
- ? headers.get(TripleHeaderEnum.SERVICE_VERSION.getHeader()).toString()
- : null;
- final String group = headers.containsKey(TripleHeaderEnum.SERVICE_GROUP.getHeader())
- ? headers.get(TripleHeaderEnum.SERVICE_GROUP.getHeader()).toString()
- : null;
- final String key = URL.buildKey(serviceName, group, version);
- Invoker> invoker = pathResolver.resolve(key);
- if (invoker == null && TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
- invoker = pathResolver.resolve(URL.buildKey(serviceName, group, "1.0.0"));
- }
- if (invoker == null && TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
- invoker = pathResolver.resolve(serviceName);
- }
- return invoker;
- }
-
- private static ServiceDescriptor findServiceDescriptor(Invoker> invoker, String serviceName, boolean hasStub)
- throws UnimplementedException {
- ServiceDescriptor result;
- if (hasStub) {
- result = getStubServiceDescriptor(invoker.getUrl(), serviceName);
- } else {
- result = getReflectionServiceDescriptor(invoker.getUrl());
+ protected RpcInvocation buildRpcInvocation(RpcInvocationBuildContext context) {
+ MethodDescriptor methodDescriptor = context.getMethodDescriptor();
+ if (methodDescriptor == null) {
+ methodDescriptor = DescriptorUtils.findMethodDescriptor(
+ context.getServiceDescriptor(), context.getMethodName(), context.isHasStub());
+ context.setMethodDescriptor(methodDescriptor);
}
- if (result == null) {
- throw new UnimplementedException("service:" + serviceName);
+ MethodMetadata methodMetadata = context.getMethodMetadata();
+ if (methodMetadata == null) {
+ methodMetadata = MethodMetadata.fromMethodDescriptor(methodDescriptor);
+ context.setMethodMetadata(methodMetadata);
}
- return result;
- }
- protected static MethodDescriptor findMethodDescriptor(
- ServiceDescriptor serviceDescriptor, String originalMethodName, boolean hasStub)
- throws UnimplementedException {
- MethodDescriptor result;
- if (hasStub) {
- result = serviceDescriptor.getMethods(originalMethodName).get(0);
- } else {
- result = findReflectionMethodDescriptor(serviceDescriptor, originalMethodName);
- }
- return result;
- }
-
- protected RpcInvocation buildRpcInvocation(
- Invoker> invoker, ServiceDescriptor serviceDescriptor, MethodDescriptor methodDescriptor) {
- final URL url = invoker.getUrl();
+ Invoker> invoker = context.getInvoker();
+ URL url = invoker.getUrl();
RpcInvocation inv = new RpcInvocation(
url.getServiceModel(),
methodDescriptor.getMethodName(),
- serviceDescriptor.getInterfaceName(),
+ context.getServiceDescriptor().getInterfaceName(),
url.getProtocolServiceKey(),
methodDescriptor.getParameterClasses(),
new Object[0]);
inv.setTargetServiceUniqueName(url.getServiceKey());
inv.setReturnTypes(methodDescriptor.getReturnTypes());
- Map headers = getHttpMetadata().headers().toSingleValueMap();
- Map requestMetadata = headersToMap(headers, () -> {
- return Optional.ofNullable(headers.get(TripleHeaderEnum.TRI_HEADER_CONVERT.getHeader()))
- .map(CharSequence::toString)
- .orElse(null);
- });
- inv.setObjectAttachments(StreamUtils.toAttachments(requestMetadata));
+ inv.setObjectAttachments(StreamUtils.toAttachments(httpMetadata.headers()));
+ inv.put(TripleConstant.REMOTE_ADDRESS_KEY, httpChannel.remoteAddress());
+ inv.getAttributes().putAll(context.getAttributes());
- inv.put("tri.remote.address", httpChannel.remoteAddress());
// customizer RpcInvocation
headerFilters.forEach(f -> f.invoke(invoker, inv));
- return inv;
- }
-
- protected static ServiceDescriptor getStubServiceDescriptor(URL url, String serviceName) {
- ServiceDescriptor serviceDescriptor;
- if (url.getServiceModel() != null) {
- serviceDescriptor = url.getServiceModel().getServiceModel();
- } else {
- serviceDescriptor = StubSuppliers.getServiceDescriptor(serviceName);
- }
- return serviceDescriptor;
- }
-
- protected static ServiceDescriptor getReflectionServiceDescriptor(URL url) {
- ProviderModel providerModel = (ProviderModel) url.getServiceModel();
- if (providerModel == null || providerModel.getServiceModel() == null) {
- return null;
- }
- return providerModel.getServiceModel();
- }
- protected static boolean isEcho(String methodName) {
- return CommonConstants.$ECHO.equals(methodName);
+ return onBuildRpcInvocationCompletion(inv);
}
- protected static boolean isGeneric(String methodName) {
- return CommonConstants.$INVOKE.equals(methodName) || CommonConstants.$INVOKE_ASYNC.equals(methodName);
- }
-
- protected static MethodDescriptor findReflectionMethodDescriptor(
- ServiceDescriptor serviceDescriptor, String methodName) {
- MethodDescriptor methodDescriptor = null;
- if (isGeneric(methodName)) {
- // There should be one and only one
- methodDescriptor = ServiceDescriptorInternalCache.genericService()
- .getMethods(methodName)
- .get(0);
- } else if (isEcho(methodName)) {
- // There should be one and only one
- return ServiceDescriptorInternalCache.echoService()
- .getMethods(methodName)
- .get(0);
- } else {
- List methodDescriptors = serviceDescriptor.getMethods(methodName);
- // try lower-case method
- if (CollectionUtils.isEmpty(methodDescriptors)) {
- final String lowerMethod = Character.toLowerCase(methodName.charAt(0)) + methodName.substring(1);
- methodDescriptors = serviceDescriptor.getMethods(lowerMethod);
- }
- if (CollectionUtils.isEmpty(methodDescriptors)) {
- return null;
- }
- // In most cases there is only one method
- if (methodDescriptors.size() == 1) {
- methodDescriptor = methodDescriptors.get(0);
- }
- // generated unary method ,use unary type
- // Response foo(Request)
- // void foo(Request,StreamObserver)
- if (methodDescriptors.size() == 2) {
- if (methodDescriptors.get(1).getRpcType() == MethodDescriptor.RpcType.SERVER_STREAM) {
- methodDescriptor = methodDescriptors.get(0);
- } else if (methodDescriptors.get(0).getRpcType() == MethodDescriptor.RpcType.SERVER_STREAM) {
- methodDescriptor = methodDescriptors.get(1);
- }
+ protected RpcInvocation onBuildRpcInvocationCompletion(RpcInvocation invocation) {
+ String timeoutString = httpMetadata.headers().getFirst(TripleHeaderEnum.SERVICE_TIMEOUT.getHeader());
+ try {
+ if (null != timeoutString) {
+ Long timeout = Long.parseLong(timeoutString);
+ invocation.put(CommonConstants.TIMEOUT_KEY, timeout);
}
+ } catch (Throwable t) {
+ LOGGER.warn(
+ PROTOCOL_FAILED_PARSE,
+ "",
+ "",
+ String.format(
+ "Failed to parse request timeout set from:%s, service=%s " + "method=%s",
+ timeoutString, context.getServiceDescriptor().getInterfaceName(), context.getMethodName()));
}
- return methodDescriptor;
+ return invocation;
}
- protected FrameworkModel getFrameworkModel() {
+ protected final FrameworkModel getFrameworkModel() {
return frameworkModel;
}
- protected HEADER getHttpMetadata() {
+ protected final HEADER getHttpMetadata() {
return httpMetadata;
}
- protected Invoker> getInvoker() {
- return invoker;
- }
-
- protected ServiceDescriptor getServiceDescriptor() {
- return serviceDescriptor;
- }
-
- protected MethodDescriptor getMethodDescriptor() {
- return methodDescriptor;
- }
-
- public void setServiceDescriptor(ServiceDescriptor serviceDescriptor) {
- this.serviceDescriptor = serviceDescriptor;
- }
-
- public void setMethodDescriptor(MethodDescriptor methodDescriptor) {
- this.methodDescriptor = methodDescriptor;
- }
-
- public void setMethodMetadata(MethodMetadata methodMetadata) {
- this.methodMetadata = methodMetadata;
- }
-
- protected RpcInvocation getRpcInvocation() {
- return rpcInvocation;
- }
-
- public void setRpcInvocation(RpcInvocation rpcInvocation) {
- this.rpcInvocation = rpcInvocation;
- }
-
- protected MethodMetadata getMethodMetadata() {
- return methodMetadata;
- }
-
- protected HttpMessageDecoder getHttpMessageDecoder() {
- return this.httpMessageDecoder;
+ public final RpcInvocationBuildContext getContext() {
+ return context;
}
- protected CodecUtils getCodecUtils() {
- return this.codecUtils;
+ protected final HttpMessageListener getHttpMessageListener() {
+ return httpMessageListener;
}
protected void setHttpMessageListener(HttpMessageListener httpMessageListener) {
this.httpMessageListener = httpMessageListener;
}
-
- protected HttpMessageListener getHttpMessageListener() {
- return httpMessageListener;
- }
-
- protected PathResolver getPathResolver() {
- return pathResolver;
- }
-
- protected final URL getUrl() {
- return url;
- }
-
- protected HttpMetadata getMetadata() {
- return httpMetadata;
- }
-
- public boolean isHasStub() {
- return hasStub;
- }
-
- protected Map headersToMap(
- Map headers, Supplier convertUpperHeaderSupplier) {
- if (headers == null) {
- return Collections.emptyMap();
- }
- Map attachments = new HashMap<>(headers.size());
- for (Map.Entry header : headers.entrySet()) {
- String key = header.getKey();
- if (key.endsWith(TripleConstant.HEADER_BIN_SUFFIX)
- && key.length() > TripleConstant.HEADER_BIN_SUFFIX.length()) {
- try {
- String realKey = key.substring(0, key.length() - TripleConstant.HEADER_BIN_SUFFIX.length());
- byte[] value = StreamUtils.decodeASCIIByte(header.getValue());
- attachments.put(realKey, value);
- } catch (Exception e) {
- LOGGER.error(PROTOCOL_FAILED_PARSE, "", "", "Failed to parse response attachment key=" + key, e);
- }
- } else {
- attachments.put(key, header.getValue());
- }
- }
-
- // try converting upper key
- Object obj = convertUpperHeaderSupplier.get();
- if (obj == null) {
- return attachments;
- }
- if (obj instanceof String) {
- String json = TriRpcStatus.decodeMessage((String) obj);
- Map map = JsonUtils.toJavaObject(json, Map.class);
- for (Map.Entry entry : map.entrySet()) {
- Object val = attachments.remove(entry.getKey());
- if (val != null) {
- attachments.put(entry.getValue(), val);
- }
- }
- } else {
- // If convertUpperHeaderSupplier does not return String, just fail...
- // Internal invocation, use INTERNAL_ERROR instead.
-
- LOGGER.error(
- INTERNAL_ERROR,
- "wrong internal invocation",
- "",
- "Triple convertNoLowerCaseHeader error, obj is not String");
- }
- return attachments;
- }
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpHandlerMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpHandlerMapping.java
new file mode 100644
index 000000000000..abc10af32124
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpHandlerMapping.java
@@ -0,0 +1,105 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.h12;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.remoting.http12.HttpResponse;
+import org.apache.dubbo.remoting.http12.message.codec.CodecUtils;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.PathResolver;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.protocol.tri.DescriptorUtils;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
+import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
+import org.apache.dubbo.rpc.protocol.tri.TripleProtocol;
+import org.apache.dubbo.rpc.protocol.tri.route.HandlerInfo;
+import org.apache.dubbo.rpc.protocol.tri.route.HandlerMapping;
+
+import java.util.List;
+
+@Activate(order = -2000)
+public class HttpHandlerMapping implements HandlerMapping {
+
+ private final FrameworkModel frameworkModel;
+ private final PathResolver pathResolver;
+ private final CodecUtils codecUtils;
+
+ public HttpHandlerMapping(FrameworkModel frameworkModel) {
+ this.frameworkModel = frameworkModel;
+ pathResolver = frameworkModel.getDefaultExtension(PathResolver.class);
+ codecUtils = frameworkModel.getBeanFactory().getOrRegisterBean(CodecUtils.class);
+ }
+
+ @Override
+ public HandlerInfo getHandler(URL url, HttpRequest request, HttpResponse response) {
+ if (!supportContentType(request.contentType())) {
+ return null;
+ }
+
+ String path = request.path();
+ List parts = StringUtils.splitToList(path, '/');
+ if (parts.size() != 3) {
+ return null;
+ }
+
+ String serviceName = parts.get(1);
+ String version = request.header(TripleHeaderEnum.SERVICE_VERSION.getHeader());
+ String group = request.header(TripleHeaderEnum.SERVICE_GROUP.getHeader());
+ String key = URL.buildKey(serviceName, group, version);
+ Invoker> invoker = pathResolver.resolve(key);
+ if (invoker == null) {
+ if (TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
+ invoker = pathResolver.resolve(URL.buildKey(serviceName, group, TripleConstant.DEFAULT_VERSION));
+ if (invoker == null) {
+ invoker = pathResolver.resolve(serviceName);
+ if (invoker == null) {
+ return null;
+ }
+ }
+ }
+ }
+
+ HandlerInfo info = new HandlerInfo();
+ info.setInvoker(invoker);
+ info.setHasStub(pathResolver.hasNativeStub(path));
+ info.setServiceDescriptor(DescriptorUtils.findServiceDescriptor(invoker, serviceName, info.isHasStub()));
+ info.setMethodName(parts.get(2));
+ determineHttpMessageCodec(info, url, request);
+ return info;
+ }
+
+ protected boolean supportContentType(String contentType) {
+ return true;
+ }
+
+ protected void determineHttpMessageCodec(HandlerInfo info, URL url, HttpRequest request) {
+ info.setHttpMessageDecoder(codecUtils.determineHttpMessageDecoder(url, frameworkModel, request.contentType()));
+ info.setHttpMessageEncoder(codecUtils.determineHttpMessageEncoder(url, frameworkModel, request.contentType()));
+ }
+
+ protected final FrameworkModel getFrameworkModel() {
+ return frameworkModel;
+ }
+
+ @Override
+ public String getType() {
+ return TripleConstant.TRIPLE_HANDLER_TYPE_HTTP;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/TripleProtocolDetector.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/TripleProtocolDetector.java
index 9c7cd7138e60..5fa91a97f7c9 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/TripleProtocolDetector.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/TripleProtocolDetector.java
@@ -20,16 +20,14 @@
import org.apache.dubbo.remoting.buffer.ByteBufferBackedChannelBuffer;
import org.apache.dubbo.remoting.buffer.ChannelBuffer;
import org.apache.dubbo.remoting.buffer.ChannelBuffers;
+import org.apache.dubbo.remoting.http12.HttpMethods;
import io.netty.handler.codec.http2.Http2CodecUtil;
-import static java.lang.Math.min;
-
public class TripleProtocolDetector implements ProtocolDetector {
public static final String HTTP_VERSION = "HTTP_VERSION";
-
- private final ChannelBuffer clientPrefaceString = new ByteBufferBackedChannelBuffer(
+ private static final ChannelBuffer CLIENT_PREFACE_STRING = new ByteBufferBackedChannelBuffer(
Http2CodecUtil.connectionPrefaceBuf().nioBuffer());
@Override
@@ -38,8 +36,8 @@ public Result detect(ChannelBuffer in) {
if (in.readableBytes() < 2) {
return Result.needMoreData();
}
- byte[] magics = new byte[5];
- in.getBytes(in.readerIndex(), magics, 0, 5);
+ byte[] magics = new byte[7];
+ in.getBytes(in.readerIndex(), magics, 0, 7);
if (isHttp(magics)) {
Result recognized = Result.recognized();
recognized.setAttribute(HTTP_VERSION, HttpVersion.HTTP1.getVersion());
@@ -48,9 +46,9 @@ public Result detect(ChannelBuffer in) {
in.resetReaderIndex();
// http2
- int prefaceLen = clientPrefaceString.readableBytes();
- int bytesRead = min(in.readableBytes(), prefaceLen);
- if (bytesRead == 0 || !ChannelBuffers.prefixEquals(in, clientPrefaceString, bytesRead)) {
+ int prefaceLen = CLIENT_PREFACE_STRING.readableBytes();
+ int bytesRead = Math.min(in.readableBytes(), prefaceLen);
+ if (bytesRead == 0 || !ChannelBuffers.prefixEquals(in, CLIENT_PREFACE_STRING, bytesRead)) {
return Result.unrecognized();
}
if (bytesRead == prefaceLen) {
@@ -62,16 +60,22 @@ public Result detect(ChannelBuffer in) {
}
private static boolean isHttp(byte[] magic) {
- if (magic[0] == 'G' && magic[1] == 'E' && magic[2] == 'T') {
- return true;
- }
- if (magic[0] == 'P' && magic[1] == 'O' && magic[2] == 'S' && magic[3] == 'T') {
- return true;
+ for (int i = 0; i < 8; i++) {
+ byte[] methodBytes = HttpMethods.HTTP_METHODS_BYTES[i];
+ int end = methodBytes.length - 1;
+ for (int j = 0; j <= end; j++) {
+ if (magic[j] != methodBytes[j]) {
+ break;
+ }
+ if (j == end) {
+ return true;
+ }
+ }
}
return false;
}
- public static enum HttpVersion {
+ public enum HttpVersion {
HTTP1("http1"),
HTTP2("http2");
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodec.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodec.java
index 96b18cf2ec3f..ac910da7ee14 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodec.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodec.java
@@ -20,6 +20,7 @@
import org.apache.dubbo.remoting.http12.exception.EncodeException;
import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
import org.apache.dubbo.remoting.http12.message.MediaType;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
import java.io.IOException;
import java.io.InputStream;
@@ -31,8 +32,6 @@
public class GrpcCompositeCodec implements HttpMessageCodec {
- private static final MediaType MEDIA_TYPE = new MediaType("application", "grpc");
-
private final ProtobufHttpMessageCodec protobufHttpMessageCodec;
private final WrapperHttpMessageCodec wrapperHttpMessageCodec;
@@ -99,7 +98,7 @@ private static void writeLength(OutputStream outputStream, int length) {
@Override
public MediaType mediaType() {
- return MEDIA_TYPE;
+ return TripleConstant.MEDIA_TYPE_GRPC;
}
private static boolean isProtobuf(Object data) {
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
index 29a7de9dfd54..8f18e8d6aa45 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
@@ -24,15 +24,14 @@
import org.apache.dubbo.remoting.http12.message.MediaType;
import org.apache.dubbo.remoting.utils.UrlUtils;
import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
@Activate
public class GrpcCompositeCodecFactory implements HttpMessageEncoderFactory, HttpMessageDecoderFactory {
- private static final MediaType MEDIA_TYPE = new MediaType("application", "grpc");
-
@Override
public HttpMessageCodec createCodec(URL url, FrameworkModel frameworkModel, String mediaType) {
- final String serializeName = UrlUtils.serializationOrDefault(url);
+ String serializeName = UrlUtils.serializationOrDefault(url);
WrapperHttpMessageCodec wrapperHttpMessageCodec = new WrapperHttpMessageCodec(url, frameworkModel);
wrapperHttpMessageCodec.setSerializeType(serializeName);
ProtobufHttpMessageCodec protobufHttpMessageCodec = new ProtobufHttpMessageCodec();
@@ -41,6 +40,6 @@ public HttpMessageCodec createCodec(URL url, FrameworkModel frameworkModel, Stri
@Override
public MediaType mediaType() {
- return MEDIA_TYPE;
+ return TripleConstant.MEDIA_TYPE_GRPC;
}
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHandlerMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHandlerMapping.java
new file mode 100644
index 000000000000..ebb7b0b1d50f
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHandlerMapping.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.h12.grpc;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
+import org.apache.dubbo.rpc.protocol.tri.h12.HttpHandlerMapping;
+import org.apache.dubbo.rpc.protocol.tri.route.HandlerInfo;
+
+@Activate(order = -3000)
+public final class GrpcHandlerMapping extends HttpHandlerMapping {
+
+ public static final GrpcCompositeCodecFactory CODEC_FACTORY = new GrpcCompositeCodecFactory();
+
+ public GrpcHandlerMapping(FrameworkModel frameworkModel) {
+ super(frameworkModel);
+ }
+
+ @Override
+ protected boolean supportContentType(String contentType) {
+ return contentType.startsWith(TripleConstant.MEDIA_TYPE_GRPC.getName());
+ }
+
+ @Override
+ protected void determineHttpMessageCodec(HandlerInfo info, URL url, HttpRequest request) {
+ HttpMessageCodec codec = CODEC_FACTORY.createCodec(url, getFrameworkModel(), request.contentType());
+ info.setHttpMessageDecoder(codec);
+ info.setHttpMessageEncoder(codec);
+ }
+
+ @Override
+ public String getType() {
+ return TripleConstant.TRIPLE_HANDLER_TYPE_GRPC;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListener.java
index de216cee5621..5885fff928a3 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListener.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListener.java
@@ -17,8 +17,11 @@
package org.apache.dubbo.rpc.protocol.tri.h12.grpc;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.io.StreamUtils;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.TimeUtils;
import org.apache.dubbo.remoting.http12.HttpHeaders;
import org.apache.dubbo.remoting.http12.exception.DecodeException;
import org.apache.dubbo.remoting.http12.exception.UnimplementedException;
@@ -27,41 +30,31 @@
import org.apache.dubbo.remoting.http12.h2.Http2TransportListener;
import org.apache.dubbo.remoting.http12.message.MethodMetadata;
import org.apache.dubbo.remoting.http12.message.StreamingDecoder;
-import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.TriRpcStatus;
import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.model.MethodDescriptor;
-import org.apache.dubbo.rpc.model.ServiceDescriptor;
-import org.apache.dubbo.rpc.protocol.tri.TripleCustomerProtocolWapper;
-import org.apache.dubbo.rpc.protocol.tri.call.AbstractServerCall;
+import org.apache.dubbo.rpc.protocol.tri.DescriptorUtils;
import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor;
import org.apache.dubbo.rpc.protocol.tri.compressor.Identity;
import org.apache.dubbo.rpc.protocol.tri.h12.HttpMessageListener;
import org.apache.dubbo.rpc.protocol.tri.h12.http2.GenericHttp2ServerTransportListener;
+import org.apache.dubbo.rpc.protocol.tri.route.RpcInvocationBuildContext;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_PARSE;
public class GrpcHttp2ServerTransportListener extends GenericHttp2ServerTransportListener
implements Http2TransportListener {
- private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(AbstractServerCall.class);
+ private static final ErrorTypeAwareLogger LOGGER =
+ LoggerFactory.getErrorTypeAwareLogger(GrpcHttp2ServerTransportListener.class);
public GrpcHttp2ServerTransportListener(H2StreamChannel h2StreamChannel, URL url, FrameworkModel frameworkModel) {
super(h2StreamChannel, url, frameworkModel);
- initialize();
- }
-
- private void initialize() {
getServerChannelObserver().setTrailersCustomizer(this::grpcTrailersCustomize);
}
@@ -78,44 +71,14 @@ private static String httpStatusToGrpcStatus(Throwable throwable) {
return String.valueOf(TriRpcStatus.INTERNAL.code.code);
}
- @Override
- protected RpcInvocation buildRpcInvocation(
- Invoker> invoker, ServiceDescriptor serviceDescriptor, MethodDescriptor methodDescriptor) {
- RpcInvocation rpcInvocation = super.buildRpcInvocation(invoker, serviceDescriptor, methodDescriptor);
- HttpHeaders headers = getHttpMetadata().headers();
- String timeoutString = headers.getFirst(GrpcHeaderNames.GRPC_TIMEOUT.getName());
- try {
- if (Objects.nonNull(timeoutString)) {
- Long timeout = GrpcUtils.parseTimeoutToMills(timeoutString);
- rpcInvocation.put("timeout", timeout);
- }
- } catch (Throwable t) {
- LOGGER.warn(
- PROTOCOL_FAILED_PARSE,
- "",
- "",
- String.format(
- "Failed to parse request timeout set from:%s, service=%s " + "method=%s",
- timeoutString,
- serviceDescriptor.getInterfaceName(),
- getMethodDescriptor().getMethodName()));
- }
- return rpcInvocation;
- }
-
@Override
protected StreamingDecoder newStreamingDecoder() {
return new GrpcStreamingDecoder();
}
@Override
- protected HttpMessageListener newHttpMessageListener() {
- Http2Header httpMetadata = getHttpMetadata();
- boolean hasStub = getPathResolver().hasNativeStub(httpMetadata.path());
- if (hasStub) {
- return GrpcHttp2ServerTransportListener.super.newHttpMessageListener();
- }
- return new LazyFindMethodListener();
+ protected HttpMessageListener buildHttpMessageListener() {
+ return getContext().isHasStub() ? super.buildHttpMessageListener() : new LazyFindMethodListener();
}
@Override
@@ -138,6 +101,28 @@ private void processGrpcHeaders(Http2Header metadata) {
}
}
+ @Override
+ protected RpcInvocation onBuildRpcInvocationCompletion(RpcInvocation invocation) {
+ String timeoutString = getHttpMetadata().headers().getFirst(GrpcHeaderNames.GRPC_TIMEOUT.getName());
+ try {
+ if (null != timeoutString) {
+ Long timeout = TimeUtils.parseTimeoutToMills(timeoutString);
+ invocation.put(CommonConstants.TIMEOUT_KEY, timeout);
+ }
+ } catch (Throwable t) {
+ LOGGER.warn(
+ PROTOCOL_FAILED_PARSE,
+ "",
+ "",
+ String.format(
+ "Failed to parse request timeout set from:%s, service=%s " + "method=%s",
+ timeoutString,
+ getContext().getServiceDescriptor().getInterfaceName(),
+ getContext().getMethodName()));
+ }
+ return invocation;
+ }
+
@Override
protected GrpcStreamingDecoder getStreamingDecoder() {
return (GrpcStreamingDecoder) super.getStreamingDecoder();
@@ -148,9 +133,9 @@ private class LazyFindMethodListener implements HttpMessageListener {
private final StreamingDecoder streamingDecoder;
private LazyFindMethodListener() {
- this.streamingDecoder = new GrpcStreamingDecoder();
- this.streamingDecoder.setFragmentListener(new DetermineMethodDescriptorListener());
- this.streamingDecoder.request(Integer.MAX_VALUE);
+ streamingDecoder = new GrpcStreamingDecoder();
+ streamingDecoder.setFragmentListener(new DetermineMethodDescriptorListener());
+ streamingDecoder.request(Integer.MAX_VALUE);
}
@Override
@@ -172,66 +157,31 @@ public void onClose() {
@Override
public void onFragmentMessage(InputStream dataHeader, InputStream rawMessage) {
try {
- ByteArrayOutputStream merge =
+ ByteArrayOutputStream merged =
new ByteArrayOutputStream(dataHeader.available() + rawMessage.available());
- transferToOutputStream(merge, dataHeader);
- ByteArrayOutputStream bos = new ByteArrayOutputStream(rawMessage.available());
- transferToOutputStream(bos, rawMessage);
- byte[] data = bos.toByteArray();
- MethodDescriptor methodDescriptor = getMethodDescriptor();
- if (methodDescriptor == null) {
- Http2Header httpMetadata = getHttpMetadata();
- String path = httpMetadata.path();
- String[] parts = path.split("/");
- String originalMethodName = parts[2];
- methodDescriptor = findReflectionMethodDescriptor(getServiceDescriptor(), originalMethodName);
- if (methodDescriptor == null) {
- List methodDescriptors =
- getServiceDescriptor().getMethods(originalMethodName);
- final TripleCustomerProtocolWapper.TripleRequestWrapper request;
- request = TripleCustomerProtocolWapper.TripleRequestWrapper.parseFrom(data);
- final String[] paramTypes = request.getArgTypes()
- .toArray(new String[request.getArgs().size()]);
- // wrapper mode the method can overload so maybe list
- for (MethodDescriptor descriptor : methodDescriptors) {
- // params type is array
- if (Arrays.equals(descriptor.getCompatibleParamSignatures(), paramTypes)) {
- methodDescriptor = descriptor;
- break;
- }
- }
- if (methodDescriptor == null) {
- throw new UnimplementedException("method:" + originalMethodName);
- }
- }
- setMethodDescriptor(methodDescriptor);
- setMethodMetadata(MethodMetadata.fromMethodDescriptor(methodDescriptor));
- setRpcInvocation(buildRpcInvocation(getInvoker(), getServiceDescriptor(), methodDescriptor));
+ StreamUtils.copy(dataHeader, merged);
+ byte[] data = StreamUtils.readBytes(rawMessage);
+
+ RpcInvocationBuildContext context = getContext();
+ if (null == context.getMethodDescriptor()) {
+ context.setMethodDescriptor(DescriptorUtils.findTripleMethodDescriptor(
+ context.getServiceDescriptor(), context.getMethodName(), data));
+
+ setHttpMessageListener(GrpcHttp2ServerTransportListener.super.buildHttpMessageListener());
+
// replace decoder
- HttpMessageListener httpMessageListener =
- GrpcHttp2ServerTransportListener.super.newHttpMessageListener();
- GrpcCompositeCodec grpcCompositeCodec = (GrpcCompositeCodec) getHttpMessageDecoder();
- grpcCompositeCodec.setDecodeTypes(getMethodMetadata().getActualRequestTypes());
- grpcCompositeCodec.setEncodeTypes(
- new Class[] {getMethodMetadata().getActualResponseType()});
- GrpcHttp2ServerTransportListener.super
- .getServerChannelObserver()
- .setResponseEncoder(grpcCompositeCodec);
- setHttpMessageListener(httpMessageListener);
+ GrpcCompositeCodec grpcCompositeCodec = (GrpcCompositeCodec) context.getHttpMessageDecoder();
+ MethodMetadata methodMetadata = context.getMethodMetadata();
+ grpcCompositeCodec.setDecodeTypes(methodMetadata.getActualRequestTypes());
+ grpcCompositeCodec.setEncodeTypes(new Class[] {methodMetadata.getActualResponseType()});
+ getServerChannelObserver().setResponseEncoder(grpcCompositeCodec);
}
- transferToOutputStream(merge, new ByteArrayInputStream(data));
- getHttpMessageListener().onMessage(new ByteArrayInputStream(merge.toByteArray()));
+
+ merged.write(data);
+ getHttpMessageListener().onMessage(new ByteArrayInputStream(merged.toByteArray()));
} catch (IOException e) {
throw new DecodeException(e);
}
}
-
- private void transferToOutputStream(OutputStream out, InputStream inputStream) throws IOException {
- byte[] bytes = new byte[1024];
- int len;
- while ((len = inputStream.read(bytes)) != -1) {
- out.write(bytes, 0, len);
- }
- }
}
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcUtils.java
deleted file mode 100644
index 889b387071a8..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcUtils.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.h12.grpc;
-
-import org.apache.dubbo.common.utils.StringUtils;
-
-import java.util.concurrent.TimeUnit;
-
-public class GrpcUtils {
-
- private GrpcUtils() {}
-
- public static Long parseTimeoutToMills(String timeoutVal) {
- if (StringUtils.isEmpty(timeoutVal) || StringUtils.isContains(timeoutVal, "null")) {
- return null;
- }
- long value = Long.parseLong(timeoutVal.substring(0, timeoutVal.length() - 1));
- char unit = timeoutVal.charAt(timeoutVal.length() - 1);
- switch (unit) {
- case 'n':
- return TimeUnit.NANOSECONDS.toMillis(value);
- case 'u':
- return TimeUnit.MICROSECONDS.toMillis(value);
- case 'm':
- return value;
- case 'S':
- return TimeUnit.SECONDS.toMillis(value);
- case 'M':
- return TimeUnit.MINUTES.toMillis(value);
- case 'H':
- return TimeUnit.HOURS.toMillis(value);
- default:
- // invalid timeout config
- return null;
- }
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/ProtobufHttpMessageCodec.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/ProtobufHttpMessageCodec.java
index 011fd6b8a933..330a44696e85 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/ProtobufHttpMessageCodec.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/ProtobufHttpMessageCodec.java
@@ -21,6 +21,7 @@
import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
import org.apache.dubbo.remoting.http12.message.MediaType;
import org.apache.dubbo.rpc.protocol.tri.SingleProtobufUtils;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
import java.io.IOException;
import java.io.InputStream;
@@ -28,8 +29,6 @@
public class ProtobufHttpMessageCodec implements HttpMessageCodec {
- private static final MediaType MEDIA_TYPE = new MediaType("application", "x-protobuf");
-
@Override
public void encode(OutputStream outputStream, Object data) throws EncodeException {
try {
@@ -50,6 +49,6 @@ public Object decode(InputStream inputStream, Class> targetType) throws Decode
@Override
public MediaType mediaType() {
- return MEDIA_TYPE;
+ return TripleConstant.MEDIA_TYPE_GRPC;
}
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java
index 389e48bac3e1..d1da3e89cd79 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java
@@ -26,10 +26,7 @@
import org.apache.dubbo.remoting.http12.h1.Http1ServerStreamChannelObserver;
import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener;
import org.apache.dubbo.remoting.http12.message.DefaultListeningDecoder;
-import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
-import org.apache.dubbo.remoting.http12.message.ListeningDecoder;
import org.apache.dubbo.remoting.http12.message.MediaType;
-import org.apache.dubbo.remoting.http12.message.MethodMetadata;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.model.FrameworkModel;
@@ -40,67 +37,59 @@
import org.apache.dubbo.rpc.protocol.tri.h12.ServerCallListener;
import org.apache.dubbo.rpc.protocol.tri.h12.ServerStreamServerCallListener;
import org.apache.dubbo.rpc.protocol.tri.h12.UnaryServerCallListener;
+import org.apache.dubbo.rpc.protocol.tri.route.RpcInvocationBuildContext;
public class DefaultHttp11ServerTransportListener
extends AbstractServerTransportListener
implements Http1ServerTransportListener {
private final HttpChannel httpChannel;
-
- private final URL url;
+ private Http1ServerChannelObserver serverChannelObserver;
public DefaultHttp11ServerTransportListener(HttpChannel httpChannel, URL url, FrameworkModel frameworkModel) {
super(frameworkModel, url, httpChannel);
- this.url = url;
this.httpChannel = httpChannel;
}
+ @Override
+ protected HttpMessageListener buildHttpMessageListener() {
+ RpcInvocationBuildContext context = getContext();
+ RpcInvocation rpcInvocation = buildRpcInvocation(context);
+
+ ServerCallListener serverCallListener =
+ startListener(rpcInvocation, context.getMethodDescriptor(), context.getInvoker());
+
+ DefaultListeningDecoder listeningDecoder = new DefaultListeningDecoder(
+ context.getHttpMessageDecoder(), context.getMethodMetadata().getActualRequestTypes());
+ listeningDecoder.setListener(serverCallListener::onMessage);
+ return new DefaultHttpMessageListener(listeningDecoder);
+ }
+
private ServerCallListener startListener(
RpcInvocation invocation, MethodDescriptor methodDescriptor, Invoker> invoker) {
switch (methodDescriptor.getRpcType()) {
case UNARY:
- Http1ServerChannelObserver http1ChannelObserver = new Http1ServerChannelObserver(httpChannel);
- http1ChannelObserver.setResponseEncoder(getCodecUtils()
- .determineHttpMessageEncoder(
- getFrameworkModel(), getHttpMetadata().headers(), getUrl()));
- return new AutoCompleteUnaryServerCallListener(invocation, invoker, http1ChannelObserver);
+ serverChannelObserver = new Http1ServerChannelObserver(httpChannel);
+ return new AutoCompleteUnaryServerCallListener(invocation, invoker, serverChannelObserver);
case SERVER_STREAM:
- Http1ServerChannelObserver serverStreamChannelObserver =
- new Http1ServerStreamChannelObserver(httpChannel);
- serverStreamChannelObserver.setResponseEncoder(getCodecUtils()
- .determineHttpMessageEncoder(
- getFrameworkModel(), getHttpMetadata().headers(), getUrl()));
- serverStreamChannelObserver.setHeadersCustomizer((headers) -> headers.set(
+ serverChannelObserver = new Http1ServerStreamChannelObserver(httpChannel);
+ serverChannelObserver.setHeadersCustomizer((headers) -> headers.set(
HttpHeaderNames.CONTENT_TYPE.getName(), MediaType.TEXT_EVENT_STREAM_VALUE.getName()));
- return new AutoCompleteServerStreamServerCallListener(invocation, invoker, serverStreamChannelObserver);
+ return new AutoCompleteServerStreamServerCallListener(invocation, invoker, serverChannelObserver);
default:
throw new UnsupportedOperationException("HTTP1.x only support unary and server-stream");
}
}
@Override
- protected HttpMessageListener newHttpMessageListener() {
- RequestMetadata httpMetadata = getHttpMetadata();
- String path = httpMetadata.path();
- String[] parts = path.split("/");
- String originalMethodName = parts[2];
- boolean hasStub = getPathResolver().hasNativeStub(path);
- MethodDescriptor methodDescriptor = findMethodDescriptor(getServiceDescriptor(), originalMethodName, hasStub);
- MethodMetadata methodMetadata = MethodMetadata.fromMethodDescriptor(methodDescriptor);
- RpcInvocation rpcInvocation = buildRpcInvocation(getInvoker(), getServiceDescriptor(), methodDescriptor);
- setMethodDescriptor(methodDescriptor);
- setMethodMetadata(methodMetadata);
- setRpcInvocation(rpcInvocation);
- ListeningDecoder listeningDecoder =
- newListeningDecoder(getHttpMessageDecoder(), methodMetadata.getActualRequestTypes());
- return new DefaultHttpMessageListener(listeningDecoder);
+ protected void onMetadataCompletion(RequestMetadata metadata) {
+ serverChannelObserver.setResponseEncoder(getContext().getHttpMessageEncoder());
+ super.onMetadataCompletion(metadata);
}
- private ListeningDecoder newListeningDecoder(HttpMessageDecoder decoder, Class>[] actualRequestTypes) {
- DefaultListeningDecoder defaultListeningDecoder = new DefaultListeningDecoder(decoder, actualRequestTypes);
- ServerCallListener serverCallListener = startListener(getRpcInvocation(), getMethodDescriptor(), getInvoker());
- defaultListeningDecoder.setListener(serverCallListener::onMessage);
- return defaultListeningDecoder;
+ @Override
+ protected void onError(Throwable throwable) {
+ serverChannelObserver.onError(throwable);
}
private static class AutoCompleteUnaryServerCallListener extends UnaryServerCallListener {
@@ -113,7 +102,7 @@ public AutoCompleteUnaryServerCallListener(
@Override
public void onMessage(Object message) {
super.onMessage(message);
- super.onComplete();
+ onComplete();
}
}
@@ -127,7 +116,7 @@ public AutoCompleteServerStreamServerCallListener(
@Override
public void onMessage(Object message) {
super.onMessage(message);
- super.onComplete();
+ onComplete();
}
}
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java
index a859ae48ae27..8669cc4e97d9 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java
@@ -19,7 +19,6 @@
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
import org.apache.dubbo.common.threadpool.serial.SerializingExecutor;
-import org.apache.dubbo.remoting.http12.RequestMetadata;
import org.apache.dubbo.remoting.http12.exception.HttpStatusException;
import org.apache.dubbo.remoting.http12.h2.H2StreamChannel;
import org.apache.dubbo.remoting.http12.h2.Http2Header;
@@ -46,31 +45,32 @@
import org.apache.dubbo.rpc.protocol.tri.h12.ServerStreamServerCallListener;
import org.apache.dubbo.rpc.protocol.tri.h12.UnaryServerCallListener;
import org.apache.dubbo.rpc.protocol.tri.h12.grpc.StreamingHttpMessageListener;
+import org.apache.dubbo.rpc.protocol.tri.route.RpcInvocationBuildContext;
import java.util.concurrent.Executor;
public class GenericHttp2ServerTransportListener extends AbstractServerTransportListener
implements Http2TransportListener {
- private final Http2ServerChannelObserver serverChannelObserver;
-
- private final H2StreamChannel h2StreamChannel;
-
private final ExecutorSupport executorSupport;
-
private final StreamingDecoder streamingDecoder;
+ private final Http2ServerChannelObserver serverChannelObserver;
private ServerCallListener serverCallListener;
public GenericHttp2ServerTransportListener(
H2StreamChannel h2StreamChannel, URL url, FrameworkModel frameworkModel) {
super(frameworkModel, url, h2StreamChannel);
- this.h2StreamChannel = h2StreamChannel;
- this.executorSupport = ExecutorRepository.getInstance(url.getOrDefaultApplicationModel())
+ executorSupport = ExecutorRepository.getInstance(url.getOrDefaultApplicationModel())
.getExecutorSupport(url);
- this.streamingDecoder = newStreamingDecoder();
- this.serverChannelObserver = new Http2ServerCallToObserverAdapter(frameworkModel, h2StreamChannel);
- this.serverChannelObserver.setStreamingDecoder(streamingDecoder);
+ streamingDecoder = newStreamingDecoder();
+ serverChannelObserver = new Http2ServerCallToObserverAdapter(frameworkModel, h2StreamChannel);
+ serverChannelObserver.setStreamingDecoder(streamingDecoder);
+ }
+
+ protected StreamingDecoder newStreamingDecoder() {
+ // default no op
+ return new NoOpStreamingDecoder();
}
@Override
@@ -79,6 +79,28 @@ protected Executor initializeExecutor(Http2Header metadata) {
return new SerializingExecutor(executor);
}
+ protected void doOnMetadata(Http2Header metadata) {
+ if (metadata.isEndStream()) {
+ return;
+ }
+ super.doOnMetadata(metadata);
+ }
+
+ @Override
+ protected HttpMessageListener buildHttpMessageListener() {
+ RpcInvocationBuildContext context = getContext();
+ RpcInvocation rpcInvocation = buildRpcInvocation(context);
+
+ serverCallListener = startListener(rpcInvocation, context.getMethodDescriptor(), context.getInvoker());
+
+ DefaultListeningDecoder listeningDecoder = new DefaultListeningDecoder(
+ context.getHttpMessageDecoder(), context.getMethodMetadata().getActualRequestTypes());
+ listeningDecoder.setListener(new Http2StreamingDecodeListener(serverCallListener));
+ streamingDecoder.setFragmentListener(new StreamingDecoder.DefaultFragmentListener(listeningDecoder));
+ getServerChannelObserver().setStreamingDecoder(streamingDecoder);
+ return new StreamingHttpMessageListener(streamingDecoder);
+ }
+
private ServerCallListener startListener(
RpcInvocation invocation, MethodDescriptor methodDescriptor, Invoker> invoker) {
Http2ServerChannelObserver responseObserver = getServerChannelObserver();
@@ -86,14 +108,13 @@ private ServerCallListener startListener(
responseObserver.setCancellationContext(cancellationContext);
switch (methodDescriptor.getRpcType()) {
case UNARY:
- Http2Header httpMetadata = getHttpMetadata();
- boolean hasStub = getPathResolver().hasNativeStub(httpMetadata.path());
boolean applyCustomizeException = false;
- if (!hasStub) {
+ if (!getContext().isHasStub()) {
+ MethodMetadata methodMetadata = getContext().getMethodMetadata();
applyCustomizeException = ReflectionPackableMethod.needWrap(
methodDescriptor,
- getMethodMetadata().getActualRequestTypes(),
- getMethodMetadata().getActualResponseType());
+ methodMetadata.getActualRequestTypes(),
+ methodMetadata.getActualResponseType());
}
UnaryServerCallListener unaryServerCallListener = startUnary(invocation, invoker, responseObserver);
unaryServerCallListener.setApplyCustomizeException(applyCustomizeException);
@@ -108,63 +129,25 @@ private ServerCallListener startListener(
}
}
- public Http2ServerChannelObserver getServerChannelObserver() {
- return serverChannelObserver;
- }
-
- @Override
- public void cancelByRemote(long errorCode) {
- this.serverChannelObserver.cancel(new HttpStatusException((int) errorCode));
- this.serverCallListener.onCancel(errorCode);
- }
-
- protected StreamingDecoder newStreamingDecoder() {
- // default no op
- return new NoOpStreamingDecoder();
+ private UnaryServerCallListener startUnary(
+ RpcInvocation invocation, Invoker> invoker, Http2ServerChannelObserver responseObserver) {
+ return new UnaryServerCallListener(invocation, invoker, responseObserver);
}
- protected void doOnMetadata(Http2Header metadata) {
- if (metadata.isEndStream()) {
- return;
- }
- super.doOnMetadata(metadata);
+ private ServerStreamServerCallListener startServerStreaming(
+ RpcInvocation invocation, Invoker> invoker, Http2ServerChannelObserver responseObserver) {
+ return new ServerStreamServerCallListener(invocation, invoker, responseObserver);
}
- @Override
- protected HttpMessageListener newHttpMessageListener() {
- RequestMetadata httpMetadata = getHttpMetadata();
- String path = httpMetadata.path();
- String[] parts = path.split("/");
- String originalMethodName = parts[2];
- MethodDescriptor methodDescriptor = getMethodDescriptor();
- if (methodDescriptor == null) {
- methodDescriptor = findMethodDescriptor(getServiceDescriptor(), originalMethodName, isHasStub());
- setMethodDescriptor(methodDescriptor);
- }
- MethodMetadata methodMetadata = getMethodMetadata();
- if (methodMetadata == null) {
- methodMetadata = MethodMetadata.fromMethodDescriptor(getMethodDescriptor());
- setMethodMetadata(methodMetadata);
- }
- RpcInvocation rpcInvocation = getRpcInvocation();
- if (rpcInvocation == null) {
- setRpcInvocation(buildRpcInvocation(getInvoker(), getServiceDescriptor(), methodDescriptor));
- }
- initializeServerCallListener();
- DefaultListeningDecoder defaultListeningDecoder = new DefaultListeningDecoder(
- getHttpMessageDecoder(), getMethodMetadata().getActualRequestTypes());
- defaultListeningDecoder.setListener(new Http2StreamingDecodeListener(serverCallListener));
- streamingDecoder.setFragmentListener(new StreamingDecoder.DefaultFragmentListener(defaultListeningDecoder));
- getServerChannelObserver().setStreamingDecoder(streamingDecoder);
- return new StreamingHttpMessageListener(streamingDecoder);
+ private BiStreamServerCallListener startBiStreaming(
+ RpcInvocation invocation, Invoker> invoker, Http2ServerChannelObserver responseObserver) {
+ return new BiStreamServerCallListener(invocation, invoker, responseObserver);
}
@Override
protected void onMetadataCompletion(Http2Header metadata) {
- super.onMetadataCompletion(metadata);
- this.serverChannelObserver.setResponseEncoder(
- getCodecUtils().determineHttpMessageEncoder(getFrameworkModel(), metadata.headers(), getUrl()));
- this.serverChannelObserver.request(1);
+ serverChannelObserver.setResponseEncoder(getContext().getHttpMessageEncoder());
+ serverChannelObserver.request(1);
}
@Override
@@ -179,8 +162,18 @@ protected void onError(Throwable throwable) {
serverChannelObserver.onError(throwable);
}
+ @Override
+ public void cancelByRemote(long errorCode) {
+ serverChannelObserver.cancel(new HttpStatusException((int) errorCode));
+ serverCallListener.onCancel(errorCode);
+ }
+
protected StreamingDecoder getStreamingDecoder() {
- return this.streamingDecoder;
+ return streamingDecoder;
+ }
+
+ protected final Http2ServerChannelObserver getServerChannelObserver() {
+ return serverChannelObserver;
}
private static class Http2StreamingDecodeListener implements ListeningDecoder.Listener {
@@ -193,37 +186,12 @@ private Http2StreamingDecodeListener(ServerCallListener serverCallListener) {
@Override
public void onMessage(Object message) {
- this.serverCallListener.onMessage(message);
+ serverCallListener.onMessage(message);
}
@Override
public void onClose() {
- this.serverCallListener.onComplete();
- }
- }
-
- private void initializeServerCallListener() {
- if (serverCallListener == null) {
- this.serverCallListener = startListener(getRpcInvocation(), getMethodDescriptor(), getInvoker());
+ serverCallListener.onComplete();
}
}
-
- private UnaryServerCallListener startUnary(
- RpcInvocation invocation, Invoker> invoker, Http2ServerChannelObserver responseObserver) {
- return new UnaryServerCallListener(invocation, invoker, responseObserver);
- }
-
- private ServerStreamServerCallListener startServerStreaming(
- RpcInvocation invocation, Invoker> invoker, Http2ServerChannelObserver responseObserver) {
- return new ServerStreamServerCallListener(invocation, invoker, responseObserver);
- }
-
- private BiStreamServerCallListener startBiStreaming(
- RpcInvocation invocation, Invoker> invoker, Http2ServerChannelObserver responseObserver) {
- return new BiStreamServerCallListener(invocation, invoker, responseObserver);
- }
-
- protected ServerCallListener getServerCallListener() {
- return serverCallListener;
- }
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerStreamObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerStreamObserver.java
index 7a0f96c282dd..58fa91996e46 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerStreamObserver.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerStreamObserver.java
@@ -63,7 +63,7 @@ public Map getResponseAttachments() {
protected HttpMetadata encodeTrailers(Throwable throwable) {
HttpMetadata httpMetadata = super.encodeTrailers(throwable);
HttpHeaders headers = httpMetadata.headers();
- StreamUtils.convertAttachment(headers, attachments, TripleProtocol.CONVERT_NO_LOWER_HEADER);
+ StreamUtils.putHeaders(headers, attachments, TripleProtocol.CONVERT_NO_LOWER_HEADER);
return httpMetadata;
}
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/observer/ServerCallToObserverAdapter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/observer/ServerCallToObserverAdapter.java
deleted file mode 100644
index f0d84f1939c2..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/observer/ServerCallToObserverAdapter.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.observer;
-
-import org.apache.dubbo.common.constants.CommonConstants;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.rpc.CancellationContext;
-import org.apache.dubbo.rpc.TriRpcStatus;
-import org.apache.dubbo.rpc.protocol.tri.CancelableStreamObserver;
-import org.apache.dubbo.rpc.protocol.tri.ServerStreamObserver;
-import org.apache.dubbo.rpc.protocol.tri.call.AbstractServerCall;
-
-import java.util.Map;
-
-public class ServerCallToObserverAdapter extends CancelableStreamObserver implements ServerStreamObserver {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(CancelableStreamObserver.class);
- public final CancellationContext cancellationContext;
- private final AbstractServerCall call;
- private Map attachments;
- private boolean terminated = false;
-
- private boolean isNeedReturnException = false;
-
- private Integer exceptionCode = CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS;
-
- public Integer getExceptionCode() {
- return exceptionCode;
- }
-
- public void setExceptionCode(Integer exceptionCode) {
- this.exceptionCode = exceptionCode;
- }
-
- public boolean isNeedReturnException() {
- return isNeedReturnException;
- }
-
- public void setNeedReturnException(boolean needReturnException) {
- isNeedReturnException = needReturnException;
- }
-
- public ServerCallToObserverAdapter(AbstractServerCall call, CancellationContext cancellationContext) {
- this.call = call;
- this.cancellationContext = cancellationContext;
- }
-
- public boolean isAutoRequestN() {
- return call.isAutoRequestN();
- }
-
- public boolean isTerminated() {
- return terminated;
- }
-
- private void setTerminated() {
- this.terminated = true;
- }
-
- @Override
- public void onNext(Object data) {
- if (isTerminated()) {
- throw new IllegalStateException("Stream observer has been terminated, no more data is allowed");
- }
- call.setExceptionCode(exceptionCode);
- call.setNeedReturnException(isNeedReturnException);
- call.sendMessage(data);
- }
-
- @Override
- public void onError(Throwable throwable) {
- final TriRpcStatus status = TriRpcStatus.getStatus(throwable);
- onCompleted(status);
- }
-
- public void onCompleted(TriRpcStatus status) {
- if (isTerminated()) {
- return;
- }
- call.setExceptionCode(exceptionCode);
- call.setNeedReturnException(isNeedReturnException);
- call.close(status, attachments);
- setTerminated();
- }
-
- @Override
- public void onCompleted() {
- onCompleted(TriRpcStatus.OK);
- }
-
- public void setResponseAttachments(Map attachments) {
- this.attachments = attachments;
- }
-
- @Override
- public void setCompression(String compression) {
- call.setCompression(compression);
- }
-
- public void cancel(Throwable throwable) {
- if (terminated) {
- return;
- }
- setTerminated();
- call.cancelByLocal(throwable);
- }
-
- public boolean isTimeout(long cost) {
- return call.timeout != null && call.timeout < cost;
- }
-
- @Override
- public void disableAutoFlowControl() {
- call.disableAutoRequestN();
- }
-
- @Override
- public void request(int count) {
- call.request(count);
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/ArgumentConverter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/ArgumentConverter.java
new file mode 100644
index 000000000000..3f8cfe7cce41
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/ArgumentConverter.java
@@ -0,0 +1,24 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest;
+
+import org.apache.dubbo.rpc.protocol.tri.rest.meta.ParameterDescriptor;
+
+public interface ArgumentConverter {
+
+ T convert(Object value, Class targetType, ParameterDescriptor parameter);
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/ArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/ArgumentResolver.java
new file mode 100644
index 000000000000..13a18d4e0a17
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/ArgumentResolver.java
@@ -0,0 +1,28 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest;
+
+import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.remoting.http12.HttpResponse;
+import org.apache.dubbo.rpc.protocol.tri.rest.meta.ParameterDescriptor;
+
+public interface ArgumentResolver {
+
+ boolean support(ParameterDescriptor parameter);
+
+ Object resolve(ParameterDescriptor parameter, HttpRequest request, HttpResponse response);
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestHttpMessageCodec.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestHttpMessageCodec.java
new file mode 100644
index 000000000000..c79c4d73a93a
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestHttpMessageCodec.java
@@ -0,0 +1,85 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest;
+
+import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.remoting.http12.HttpResponse;
+import org.apache.dubbo.remoting.http12.exception.DecodeException;
+import org.apache.dubbo.remoting.http12.exception.EncodeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;
+import org.apache.dubbo.remoting.http12.message.MediaType;
+import org.apache.dubbo.rpc.protocol.tri.rest.meta.ParameterDescriptor;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class RestHttpMessageCodec implements HttpMessageCodec {
+
+ private final HttpRequest request;
+ private final HttpResponse response;
+ private final ParameterDescriptor[] parameters;
+ private final HttpMessageDecoder httpMessageDecoder;
+ private final HttpMessageEncoder httpMessageEncoder;
+ private final ArgumentResolver argumentResolver;
+ private final ArgumentConverter argumentConverter;
+
+ public RestHttpMessageCodec(
+ HttpRequest request,
+ HttpResponse response,
+ ParameterDescriptor[] parameters,
+ HttpMessageDecoder httpMessageDecoder,
+ HttpMessageEncoder httpMessageEncoder,
+ ArgumentResolver argumentResolver,
+ ArgumentConverter argumentConverter) {
+ this.request = request;
+ this.response = response;
+ this.parameters = parameters;
+ this.httpMessageDecoder = httpMessageDecoder;
+ this.httpMessageEncoder = httpMessageEncoder;
+ this.argumentResolver = argumentResolver;
+ this.argumentConverter = argumentConverter;
+ }
+
+ @Override
+ public Object decode(InputStream inputStream, Class> targetType) throws DecodeException {
+ return decode(inputStream, new Class>[] {targetType});
+ }
+
+ @Override
+ public Object[] decode(InputStream inputStream, Class>[] targetTypes) throws DecodeException {
+ int len = parameters.length;
+ Object[] args = new Object[len];
+ for (int i = 0; i < len; i++) {
+ ParameterDescriptor parameter = parameters[i];
+ Object arg = argumentResolver.resolve(parameter, request, response);
+ args[i] = argumentConverter.convert(arg, parameter.getType(), parameter);
+ }
+ return args;
+ }
+
+ @Override
+ public MediaType mediaType() {
+ return MediaType.ALL_VALUE;
+ }
+
+ @Override
+ public void encode(OutputStream outputStream, Object data) throws EncodeException {
+ httpMessageEncoder.encode(outputStream, data);
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestInvokeFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestInvokeFilter.java
new file mode 100644
index 000000000000..44d696d400e6
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestInvokeFilter.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.rpc.BaseFilter;
+import org.apache.dubbo.rpc.Filter;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+
+@Activate(group = CommonConstants.PROVIDER, order = Integer.MIN_VALUE + 200)
+public class RestInvokeFilter implements Filter, BaseFilter.Listener {
+
+ @Override
+ public Result invoke(Invoker> invoker, Invocation invocation) throws RpcException {
+ return null;
+ }
+
+ @Override
+ public void onResponse(Result appResponse, Invoker> invoker, Invocation invocation) {}
+
+ @Override
+ public void onError(Throwable t, Invoker> invoker, Invocation invocation) {}
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
new file mode 100644
index 000000000000..2f48995d6751
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
@@ -0,0 +1,100 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.remoting.http12.HttpResponse;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
+import org.apache.dubbo.rpc.protocol.tri.rest.meta.MappingDescriptor;
+import org.apache.dubbo.rpc.protocol.tri.route.HandlerInfo;
+import org.apache.dubbo.rpc.protocol.tri.route.HandlerMapping;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+@Activate(order = -1000)
+public class DefaultRequestMappingRegistry implements RequestMappingRegistry, HandlerMapping {
+
+ private final Map> directMappings = new HashMap<>();
+ private final RadixTree treeMappings = new RadixTree<>();
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final Lock readLook = lock.readLock();
+
+ @Override
+ public void register(Invoker> invoker) {}
+
+ @Override
+ public void unregister(Invoker> invoker) {
+ Class> serviceClass =
+ invoker.getUrl().getServiceModel().getProxyObject().getClass();
+ }
+
+ @Override
+ public void destroy() {
+ lock.writeLock().lock();
+ try {
+ directMappings.clear();
+ treeMappings.clear();
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public HandlerInfo getHandler(URL url, HttpRequest request, HttpResponse response) {
+ MappingDescriptor descriptor = lookup(request);
+
+ if (descriptor == null) {
+ return null;
+ }
+
+ HandlerInfo info = new HandlerInfo();
+ info.setHasStub(descriptor.isHasStub());
+ info.setInvoker(descriptor.getInvoker());
+ info.setMethodMetadata(descriptor.getMethodMetadata());
+ info.setServiceDescriptor(descriptor.getServiceDescriptor());
+ info.setMethodDescriptor(descriptor.getMethodDescriptor());
+ return info;
+ }
+
+ protected final MappingDescriptor lookup(HttpRequest request) {
+ readLook.lock();
+ try {
+ List matched = directMappings.get(request.path());
+ matched = treeMappings.match(request.path());
+
+ if (!matched.isEmpty()) {
+ return matched.get(0).getDescriptor();
+ }
+ } finally {
+ readLook.unlock();
+ }
+ return null;
+ }
+
+ @Override
+ public String getType() {
+ return TripleConstant.TRIPLE_HANDLER_TYPE_REST;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/MethodWalker.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/MethodWalker.java
new file mode 100644
index 000000000000..d2860065c931
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/MethodWalker.java
@@ -0,0 +1,26 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping;
+
+import org.springframework.asm.MethodVisitor;
+
+public final class MethodWalker {
+
+ public void walk(Class> clazz, MethodVisitor visitor) {}
+
+ public interface MethodVisitor {}
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java
new file mode 100644
index 000000000000..6c9f0ef61681
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java
@@ -0,0 +1,28 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping;
+
+import java.util.List;
+
+public class RadixTree {
+
+ public void clear() {}
+
+ public List match(String path) {
+ return null;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
new file mode 100644
index 000000000000..3d16086bd3fa
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
@@ -0,0 +1,45 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping;
+
+import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.Condition;
+import org.apache.dubbo.rpc.protocol.tri.rest.meta.MappingDescriptor;
+
+public class RequestMapping implements Condition {
+
+ private MappingDescriptor descriptor;
+
+ @Override
+ public RequestMapping combine(RequestMapping other) {
+ return null;
+ }
+
+ @Override
+ public RequestMapping match(HttpRequest request) {
+ return null;
+ }
+
+ @Override
+ public int compareTo(RequestMapping other, HttpRequest request) {
+ return 0;
+ }
+
+ public MappingDescriptor getDescriptor() {
+ return descriptor;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
new file mode 100644
index 000000000000..95121923cc17
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping;
+
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
+
+/**
+ * RequestMappingRegistry used for registering and unregistering rest request mappings.
+ */
+@SPI(value = TripleConstant.TRIPLE_HANDLER_TYPE_REST, scope = ExtensionScope.FRAMEWORK)
+public interface RequestMappingRegistry {
+
+ void register(Invoker> invoker);
+
+ void unregister(Invoker> invoker);
+
+ void destroy();
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/AbstractCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/AbstractCondition.java
new file mode 100644
index 000000000000..34a2094ac293
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/AbstractCondition.java
@@ -0,0 +1,22 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition;
+
+import org.apache.dubbo.remoting.http12.HttpRequest;
+
+public abstract class AbstractCondition, R extends HttpRequest>
+ implements Condition {}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/Condition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/Condition.java
new file mode 100644
index 000000000000..aa34a44be67c
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/Condition.java
@@ -0,0 +1,28 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition;
+
+import org.apache.dubbo.remoting.http12.HttpRequest;
+
+public interface Condition {
+
+ T combine(T other);
+
+ T match(R request);
+
+ int compareTo(T other, R request);
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java
new file mode 100644
index 000000000000..4b18337422e3
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java
@@ -0,0 +1,19 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition;
+
+public class ConsumesCondition {}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/HeadersCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/HeadersCondition.java
new file mode 100644
index 000000000000..27512e731c96
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/HeadersCondition.java
@@ -0,0 +1,19 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition;
+
+public class HeadersCondition {}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java
new file mode 100644
index 000000000000..8a988fc8d528
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java
@@ -0,0 +1,19 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition;
+
+public class MethodsCondition {}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ParamsCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ParamsCondition.java
new file mode 100644
index 000000000000..a327af02cf25
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ParamsCondition.java
@@ -0,0 +1,19 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition;
+
+public class ParamsCondition {}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathsCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathsCondition.java
new file mode 100644
index 000000000000..48fb2b6c7f56
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathsCondition.java
@@ -0,0 +1,19 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition;
+
+public class PathsCondition {}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java
new file mode 100644
index 000000000000..1c4cc068f0d5
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java
@@ -0,0 +1,19 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition;
+
+public class ProducesCondition {}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/meta/MappingDescriptor.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/meta/MappingDescriptor.java
new file mode 100644
index 000000000000..410323aa6a34
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/meta/MappingDescriptor.java
@@ -0,0 +1,71 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.meta;
+
+import org.apache.dubbo.remoting.http12.message.MethodMetadata;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.model.MethodDescriptor;
+import org.apache.dubbo.rpc.model.ServiceDescriptor;
+
+public final class MappingDescriptor {
+
+ private final Invoker> invoker;
+ private final boolean hasStub;
+ private final ParameterDescriptor[] parameterDescriptors;
+ private final MethodMetadata methodMetadata;
+ private final MethodDescriptor methodDescriptor;
+ private final ServiceDescriptor serviceDescriptor;
+
+ public MappingDescriptor(
+ Invoker> invoker,
+ boolean hasStub,
+ ParameterDescriptor[] parameterDescriptors,
+ MethodMetadata methodMetadata,
+ MethodDescriptor methodDescriptor,
+ ServiceDescriptor serviceDescriptor) {
+ this.invoker = invoker;
+ this.hasStub = hasStub;
+ this.parameterDescriptors = parameterDescriptors;
+ this.methodMetadata = methodMetadata;
+ this.methodDescriptor = methodDescriptor;
+ this.serviceDescriptor = serviceDescriptor;
+ }
+
+ public Invoker> getInvoker() {
+ return invoker;
+ }
+
+ public boolean isHasStub() {
+ return hasStub;
+ }
+
+ public ParameterDescriptor[] getParameterDescriptors() {
+ return parameterDescriptors;
+ }
+
+ public MethodMetadata getMethodMetadata() {
+ return methodMetadata;
+ }
+
+ public MethodDescriptor getMethodDescriptor() {
+ return methodDescriptor;
+ }
+
+ public ServiceDescriptor getServiceDescriptor() {
+ return serviceDescriptor;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/meta/ParameterDescriptor.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/meta/ParameterDescriptor.java
new file mode 100644
index 000000000000..0fbff464fd2a
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/meta/ParameterDescriptor.java
@@ -0,0 +1,51 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.meta;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+public final class ParameterDescriptor {
+
+ private final String name;
+ private final Class> type;
+ private final Type genericType;
+ private final Annotation[] annotations;
+
+ public ParameterDescriptor(String name, Class> type, Type genericType, Annotation[] annotations) {
+ this.name = name;
+ this.type = type;
+ this.genericType = genericType;
+ this.annotations = annotations;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Class> getType() {
+ return type;
+ }
+
+ public Type getGenericType() {
+ return genericType;
+ }
+
+ public Annotation[] getAnnotations() {
+ return annotations;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/resteasy/.gitkeeper b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/resteasy/.gitkeeper
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/.gitkeeper b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/.gitkeeper
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpMessageAdapterFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpMessageAdapterFactory.java
new file mode 100644
index 000000000000..6282494f2464
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpMessageAdapterFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.remoting.http12.HttpChannel;
+import org.apache.dubbo.remoting.http12.HttpMetadata;
+import org.apache.dubbo.remoting.http12.HttpResponse;
+import org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory;
+
+@Activate(order = -100, onClass = "javax.servlet.http.HttpServletRequest")
+public final class ServletHttpMessageAdapterFactory
+ implements HttpMessageAdapterFactory {
+
+ @Override
+ public ServletHttpRequestAdaptee adapterRequest(HttpMetadata rawRequest, HttpChannel channel) {
+ return new ServletHttpRequestAdaptee(rawRequest, channel);
+ }
+
+ @Override
+ public HttpResponse adapterResponse(ServletHttpRequestAdaptee request, HttpMetadata rawRequest, Void rawResponse) {
+ return new ServletHttpResponseAdaptee();
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpRequestAdaptee.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpRequestAdaptee.java
new file mode 100644
index 000000000000..e6cde73a88e8
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpRequestAdaptee.java
@@ -0,0 +1,385 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
+
+import org.apache.dubbo.remoting.http12.HttpChannel;
+import org.apache.dubbo.remoting.http12.HttpMetadata;
+import org.apache.dubbo.remoting.http12.message.DefaultHttpRequest;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpUpgradeHandler;
+import javax.servlet.http.Part;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+public final class ServletHttpRequestAdaptee extends DefaultHttpRequest implements HttpServletRequest {
+
+ public ServletHttpRequestAdaptee(HttpMetadata metadata, HttpChannel channel) {
+ super(metadata, channel);
+ }
+
+ @Override
+ public String getAuthType() {
+ return null;
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ return new Cookie[0];
+ }
+
+ @Override
+ public long getDateHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getHeaders(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getHeaderNames() {
+ return null;
+ }
+
+ @Override
+ public int getIntHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ return null;
+ }
+
+ @Override
+ public String getPathInfo() {
+ return null;
+ }
+
+ @Override
+ public String getPathTranslated() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ @Override
+ public String getQueryString() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return null;
+ }
+
+ @Override
+ public boolean isUserInRole(String role) {
+ return false;
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return null;
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ return null;
+ }
+
+ @Override
+ public String getRequestURI() {
+ return null;
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return null;
+ }
+
+ @Override
+ public String getServletPath() {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession(boolean create) {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return null;
+ }
+
+ @Override
+ public String changeSessionId() {
+ return null;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
+ return false;
+ }
+
+ @Override
+ public void login(String username, String password) throws ServletException {}
+
+ @Override
+ public void logout() throws ServletException {}
+
+ @Override
+ public Collection getParts() throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public Part getPart(String name) throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public T upgrade(Class handlerClass) throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String env) throws UnsupportedEncodingException {}
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ return new String[0];
+ }
+
+ @Override
+ public Map getParameterMap() {
+ return null;
+ }
+
+ @Override
+ public String getProtocol() {
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ return null;
+ }
+
+ @Override
+ public String getServerName() {
+ return null;
+ }
+
+ @Override
+ public int getServerPort() {
+ return 0;
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return null;
+ }
+
+ @Override
+ public void removeAttribute(String name) {}
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public Enumeration getLocales() {
+ return null;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ @Override
+ public int getRemotePort() {
+ return 0;
+ }
+
+ @Override
+ public String getLocalName() {
+ return null;
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ return 0;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
+ throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ return false;
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ return true;
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ return null;
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ return DispatcherType.REQUEST;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpResponseAdaptee.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpResponseAdaptee.java
new file mode 100644
index 000000000000..8f988b64b749
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpResponseAdaptee.java
@@ -0,0 +1,137 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
+
+import org.apache.dubbo.remoting.http12.message.DefaultHttpResponse;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Locale;
+
+public class ServletHttpResponseAdaptee extends DefaultHttpResponse implements HttpServletResponse {
+
+ @Override
+ public void addCookie(Cookie cookie) {}
+
+ @Override
+ public boolean containsHeader(String name) {
+ return false;
+ }
+
+ @Override
+ public String encodeURL(String url) {
+ return null;
+ }
+
+ @Override
+ public String encodeRedirectURL(String url) {
+ return null;
+ }
+
+ @Override
+ public String encodeUrl(String url) {
+ return null;
+ }
+
+ @Override
+ public String encodeRedirectUrl(String url) {
+ return null;
+ }
+
+ @Override
+ public void setDateHeader(String name, long date) {}
+
+ @Override
+ public void addDateHeader(String name, long date) {}
+
+ @Override
+ public void setIntHeader(String name, int value) {}
+
+ @Override
+ public void addIntHeader(String name, int value) {}
+
+ @Override
+ public void setStatus(int sc, String sm) {}
+
+ @Override
+ public String getHeader(String name) {
+ return null;
+ }
+
+ @Override
+ public Collection getHeaders(String name) {
+ return null;
+ }
+
+ @Override
+ public Collection getHeaderNames() {
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public PrintWriter getWriter() throws IOException {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String charset) {}
+
+ @Override
+ public void setContentLength(int len) {}
+
+ @Override
+ public void setContentLengthLong(long len) {}
+
+ @Override
+ public void setBufferSize(int size) {}
+
+ @Override
+ public int getBufferSize() {
+ return 0;
+ }
+
+ @Override
+ public void flushBuffer() throws IOException {}
+
+ @Override
+ public void setLocale(Locale loc) {}
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/.gitkeeper b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/.gitkeeper
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/DefaultRequestRouter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/DefaultRequestRouter.java
new file mode 100644
index 000000000000..06f854382cde
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/DefaultRequestRouter.java
@@ -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 org.apache.dubbo.rpc.protocol.tri.route;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionAccessor;
+import org.apache.dubbo.common.extension.ExtensionAccessorAware;
+import org.apache.dubbo.remoting.http12.*;
+import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
+
+import java.util.List;
+
+public final class DefaultRequestRouter implements ExtensionAccessorAware, RequestRouter {
+
+ private HttpMessageAdapterFactory httpMessageAdapterFactory;
+ private List handlerMappings;
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void setExtensionAccessor(ExtensionAccessor extensionAccessor) {
+ httpMessageAdapterFactory = extensionAccessor
+ .getExtensionLoader(HttpMessageAdapterFactory.class)
+ .getActivateExtensions()
+ .get(0);
+ handlerMappings =
+ extensionAccessor.getExtensionLoader(HandlerMapping.class).getActivateExtensions();
+ }
+
+ @Override
+ public RpcInvocationBuildContext route(URL url, RequestMetadata metadata, HttpChannel httpChannel) {
+ HttpRequest request = httpMessageAdapterFactory.adapterRequest(metadata, httpChannel);
+ HttpResponse response = httpMessageAdapterFactory.adapterResponse(request, metadata);
+
+ for (int i = 0, len = handlerMappings.size(); i < len; i++) {
+ HandlerMapping handlerMapping = handlerMappings.get(i);
+ HandlerInfo info = handlerMapping.getHandler(url, request, response);
+ if (info == null) {
+ continue;
+ }
+ info.setAttribute(TripleConstant.HANDLER_TYPE_KEY, handlerMapping.getType());
+ info.setAttribute(TripleConstant.HTTP_REQUEST_KEY, request);
+ info.setAttribute(TripleConstant.HTTP_RESPONSE_KEY, response);
+ return info;
+ }
+
+ if (null != request.contentType()) {
+ throw new UnsupportedMediaTypeException(request.contentType());
+ }
+
+ return null;
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/HandlerInfo.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/HandlerInfo.java
new file mode 100644
index 000000000000..7bc55e3efe40
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/HandlerInfo.java
@@ -0,0 +1,126 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.route;
+
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;
+import org.apache.dubbo.remoting.http12.message.MethodMetadata;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.model.MethodDescriptor;
+import org.apache.dubbo.rpc.model.ServiceDescriptor;
+
+import java.util.Map;
+
+public final class HandlerInfo implements RpcInvocationBuildContext {
+
+ private Invoker> invoker;
+ private boolean hasStub;
+ private String methodName;
+ private MethodDescriptor methodDescriptor;
+ private MethodMetadata methodMetadata;
+ private ServiceDescriptor serviceDescriptor;
+ private HttpMessageDecoder httpMessageDecoder;
+ private HttpMessageEncoder httpMessageEncoder;
+ private Map attributes;
+
+ @Override
+ public Invoker> getInvoker() {
+ return invoker;
+ }
+
+ public void setInvoker(Invoker> invoker) {
+ this.invoker = invoker;
+ }
+
+ @Override
+ public boolean isHasStub() {
+ return hasStub;
+ }
+
+ public void setHasStub(boolean hasStub) {
+ this.hasStub = hasStub;
+ }
+
+ @Override
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ @Override
+ public MethodDescriptor getMethodDescriptor() {
+ return methodDescriptor;
+ }
+
+ @Override
+ public MethodMetadata getMethodMetadata() {
+ return methodMetadata;
+ }
+
+ @Override
+ public void setMethodMetadata(MethodMetadata methodMetadata) {
+ this.methodMetadata = methodMetadata;
+ }
+
+ @Override
+ public void setMethodDescriptor(MethodDescriptor methodDescriptor) {
+ this.methodDescriptor = methodDescriptor;
+ }
+
+ @Override
+ public ServiceDescriptor getServiceDescriptor() {
+ return serviceDescriptor;
+ }
+
+ public void setServiceDescriptor(ServiceDescriptor serviceDescriptor) {
+ this.serviceDescriptor = serviceDescriptor;
+ }
+
+ @Override
+ public HttpMessageDecoder getHttpMessageDecoder() {
+ return httpMessageDecoder;
+ }
+
+ public void setHttpMessageDecoder(HttpMessageDecoder httpMessageDecoder) {
+ this.httpMessageDecoder = httpMessageDecoder;
+ }
+
+ @Override
+ public HttpMessageEncoder getHttpMessageEncoder() {
+ return httpMessageEncoder;
+ }
+
+ public void setHttpMessageEncoder(HttpMessageEncoder httpMessageEncoder) {
+ this.httpMessageEncoder = httpMessageEncoder;
+ }
+
+ @Override
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ public void setAttributes(Map attributes) {
+ this.attributes = attributes;
+ }
+
+ public void setAttribute(String key, Object value) {
+ attributes.put(key, value);
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/HandlerMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/HandlerMapping.java
new file mode 100644
index 000000000000..78dbe9d79890
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/HandlerMapping.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.route;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.remoting.http12.HttpResponse;
+
+@SPI(scope = ExtensionScope.FRAMEWORK)
+public interface HandlerMapping {
+
+ HandlerInfo getHandler(URL url, HttpRequest request, HttpResponse response);
+
+ String getType();
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/RequestRouter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/RequestRouter.java
new file mode 100644
index 000000000000..2f2cf913c2f9
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/RequestRouter.java
@@ -0,0 +1,30 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.route;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.remoting.http12.HttpChannel;
+import org.apache.dubbo.remoting.http12.RequestMetadata;
+
+@SPI(value = CommonConstants.TRIPLE, scope = ExtensionScope.FRAMEWORK)
+public interface RequestRouter {
+
+ RpcInvocationBuildContext route(URL url, RequestMetadata metadata, HttpChannel httpChannel);
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/RpcInvocationBuildContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/RpcInvocationBuildContext.java
new file mode 100644
index 000000000000..1bf6bc629c5a
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/route/RpcInvocationBuildContext.java
@@ -0,0 +1,51 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.tri.route;
+
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;
+import org.apache.dubbo.remoting.http12.message.MethodMetadata;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.model.MethodDescriptor;
+import org.apache.dubbo.rpc.model.ServiceDescriptor;
+
+import java.util.Map;
+
+public interface RpcInvocationBuildContext {
+
+ Invoker> getInvoker();
+
+ boolean isHasStub();
+
+ String getMethodName();
+
+ MethodMetadata getMethodMetadata();
+
+ void setMethodMetadata(MethodMetadata methodMetadata);
+
+ MethodDescriptor getMethodDescriptor();
+
+ void setMethodDescriptor(MethodDescriptor methodDescriptor);
+
+ ServiceDescriptor getServiceDescriptor();
+
+ HttpMessageDecoder getHttpMessageDecoder();
+
+ HttpMessageEncoder getHttpMessageEncoder();
+
+ Map getAttributes();
+}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/service/TriBuiltinService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/service/TriBuiltinService.java
index b45a40ef069e..6ec289195e7f 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/service/TriBuiltinService.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/service/TriBuiltinService.java
@@ -68,8 +68,8 @@ public void init() {
healthStatusManager = new HealthStatusManager(new TriHealthImpl());
healthService = healthStatusManager.getHealthService();
reflectionServiceV1Alpha = new ReflectionV1AlphaService();
- proxyFactory = frameworkModel.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
- pathResolver = frameworkModel.getExtensionLoader(PathResolver.class).getDefaultExtension();
+ proxyFactory = frameworkModel.getAdaptiveExtension(ProxyFactory.class);
+ pathResolver = frameworkModel.getDefaultExtension(PathResolver.class);
addSingleBuiltinService(DubboHealthTriple.SERVICE_NAME, healthService, Health.class);
addSingleBuiltinService(
ReflectionV1AlphaService.SERVICE_NAME, reflectionServiceV1Alpha, ReflectionV1AlphaService.class);
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/ServerStream.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/ServerStream.java
deleted file mode 100644
index 88f45284d4e6..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/ServerStream.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.stream;
-
-import org.apache.dubbo.rpc.TriRpcStatus;
-
-import java.util.Map;
-
-import io.netty.util.concurrent.Future;
-
-/**
- * ServerStream is used to send response to client and receive requests from client. {@link
- * Listener} is used to receive requests from client.
- */
-public interface ServerStream extends Stream {
-
- interface Listener extends Stream.Listener {
-
- /**
- * Callback when receive headers
- *
- * @param headers headers received from remote peer
- */
- void onHeader(Map headers);
-
- /**
- * Callback when no more data from client side
- */
- void onComplete();
- }
-
- /**
- * Complete the stream, send response to client
- *
- * @param status response status
- * @param attachments response attachments
- * @return a future that indicates the completion of send trailers
- */
- Future> complete(
- TriRpcStatus status, Map attachments, boolean isNeedReturnException, int exceptionCode);
-
- /**
- * Send message to client
- *
- * @param message raw message
- * @param compressFlag whether to compress the message
- * @return a future that indicates the completion of send message
- */
- Future> sendMessage(byte[] message, int compressFlag);
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/StreamUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/StreamUtils.java
index b1ec7306a00a..2494505b0a64 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/StreamUtils.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/StreamUtils.java
@@ -18,6 +18,7 @@
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.JsonUtils;
import org.apache.dubbo.common.utils.LRU2Cache;
import org.apache.dubbo.remoting.http12.HttpHeaders;
@@ -28,17 +29,22 @@
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.function.BiConsumer;
+import io.netty.handler.codec.DateFormatter;
import io.netty.handler.codec.http2.DefaultHttp2Headers;
+import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_PARSE;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNSUPPORTED;
-public class StreamUtils {
+public final class StreamUtils {
- protected static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(StreamUtils.class);
+ private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(StreamUtils.class);
private static final Base64.Decoder BASE64_DECODER = Base64.getDecoder();
private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder().withoutPadding();
@@ -47,163 +53,188 @@ public class StreamUtils {
private static final Map lruHeaderMap = new LRU2Cache<>(MAX_LRU_HEADER_MAP_SIZE);
+ private StreamUtils() {}
+
public static String encodeBase64ASCII(byte[] in) {
- byte[] bytes = encodeBase64(in);
- return new String(bytes, StandardCharsets.US_ASCII);
+ return new String(encodeBase64(in), StandardCharsets.US_ASCII);
}
public static byte[] encodeBase64(byte[] in) {
return BASE64_ENCODER.encode(in);
}
- public static byte[] decodeASCIIByte(CharSequence value) {
- return BASE64_DECODER.decode(value.toString().getBytes(StandardCharsets.US_ASCII));
+ public static byte[] decodeASCIIByte(String value) {
+ return BASE64_DECODER.decode(value.getBytes(StandardCharsets.US_ASCII));
}
- public static Map toAttachments(Map origin) {
- if (origin == null || origin.isEmpty()) {
- return Collections.emptyMap();
- }
- Map res = new HashMap<>(origin.size());
- origin.forEach((k, v) -> {
- if (TripleHeaderEnum.containsExcludeAttachments(k)) {
- return;
- }
- res.put(k, v);
- });
- return res;
+ /**
+ * Parse and put attachments into headers.
+ * Ignore Http2 PseudoHeaderName and internal name.
+ * Only strings, dates, and byte arrays are allowed.
+ *
+ * @param headers the headers
+ * @param attachments the attachments
+ * @param needConvertHeaderKey whether need to convert the header key to lower-case
+ */
+ public static void putHeaders(
+ DefaultHttp2Headers headers, Map attachments, boolean needConvertHeaderKey) {
+ putHeaders(attachments, needConvertHeaderKey, headers::set);
}
/**
- * Parse and put the KV pairs into metadata. Ignore Http2 PseudoHeaderName and internal name.
- * Only raw byte array or string value will be put.
+ * Parse and put attachments into headers.
+ * Ignore Http2 PseudoHeaderName and internal name.
+ * Only strings, dates, and byte arrays are allowed.
*
- * @param headers the metadata holder
- * @param attachments KV pairs
- * @param needConvertHeaderKey convert flag
+ * @param headers the headers
+ * @param attachments the attachments
+ * @param needConvertHeaderKey whether need to convert the header key to lower-case
*/
- public static void convertAttachment(
- DefaultHttp2Headers headers, Map attachments, boolean needConvertHeaderKey) {
- if (attachments == null) {
- return;
- }
- Map needConvertKey = new HashMap<>();
- for (Map.Entry entry : attachments.entrySet()) {
- String key = lruHeaderMap.get(entry.getKey());
- if (key == null) {
- final String lowerCaseKey = entry.getKey().toLowerCase(Locale.ROOT);
- lruHeaderMap.put(entry.getKey(), lowerCaseKey);
- key = lowerCaseKey;
- }
- if (TripleHeaderEnum.containsExcludeAttachments(key)) {
- continue;
- }
- final Object v = entry.getValue();
- if (v == null) {
- continue;
- }
- if (needConvertHeaderKey && !key.equals(entry.getKey())) {
- needConvertKey.put(key, entry.getKey());
- }
- convertSingleAttachment(headers, key, v);
- }
- if (!needConvertKey.isEmpty()) {
- String needConvertJson = JsonUtils.toJson(needConvertKey);
- headers.add(TripleHeaderEnum.TRI_HEADER_CONVERT.getHeader(), TriRpcStatus.encodeMessage(needConvertJson));
- }
+ public static void putHeaders(HttpHeaders headers, Map attachments, boolean needConvertHeaderKey) {
+ putHeaders(attachments, needConvertHeaderKey, headers::set);
}
- public static void convertAttachment(
- HttpHeaders headers, Map attachments, boolean needConvertHeaderKey) {
- if (attachments == null) {
+ private static void putHeaders(
+ Map attachments, boolean needConvertHeaderKey, BiConsumer consumer) {
+ if (CollectionUtils.isEmptyMap(attachments)) {
return;
}
- Map needConvertKey = new HashMap<>();
+ Map needConvertKeys = new HashMap<>();
for (Map.Entry entry : attachments.entrySet()) {
- String key = lruHeaderMap.get(entry.getKey());
- if (key == null) {
- final String lowerCaseKey = entry.getKey().toLowerCase(Locale.ROOT);
- lruHeaderMap.put(entry.getKey(), lowerCaseKey);
- key = lowerCaseKey;
- }
- if (TripleHeaderEnum.containsExcludeAttachments(key)) {
+ Object value = entry.getValue();
+ if (value == null) {
continue;
}
- final Object v = entry.getValue();
- if (v == null) {
+
+ String key = entry.getKey();
+ String lowerCaseKey = lruHeaderMap.computeIfAbsent(key, k -> k.toLowerCase(Locale.ROOT));
+ if (TripleHeaderEnum.containsExcludeAttachments(lowerCaseKey)) {
continue;
}
- if (needConvertHeaderKey && !key.equals(entry.getKey())) {
- needConvertKey.put(key, entry.getKey());
+ if (needConvertHeaderKey && !lowerCaseKey.equals(key)) {
+ needConvertKeys.put(lowerCaseKey, key);
}
- convertSingleAttachment(headers, key, v);
+ putHeader(consumer, lowerCaseKey, value);
}
- if (!needConvertKey.isEmpty()) {
- String needConvertJson = JsonUtils.toJson(needConvertKey);
- headers.set(TripleHeaderEnum.TRI_HEADER_CONVERT.getHeader(), TriRpcStatus.encodeMessage(needConvertJson));
+ if (needConvertKeys.isEmpty()) {
+ return;
}
- }
-
- public static void convertAttachment(DefaultHttp2Headers headers, Map attachments) {
- convertAttachment(headers, attachments, false);
+ consumer.accept(
+ TripleHeaderEnum.TRI_HEADER_CONVERT.getHeader(),
+ TriRpcStatus.encodeMessage(JsonUtils.toJson(needConvertKeys)));
}
/**
- * Convert each user's attach value to metadata
+ * Put a KV pairs into headers.
*
- * @param headers outbound headers
- * @param key metadata key
- * @param v metadata value (Metadata Only string and byte arrays are allowed)
+ * @param consumer outbound headers consumer
+ * @param key the key of the attachment
+ * @param value the value of the attachment (Only strings, dates, and byte arrays are allowed in the attachment value.)
*/
- private static void convertSingleAttachment(DefaultHttp2Headers headers, String key, Object v) {
+ private static void putHeader(BiConsumer consumer, String key, Object value) {
try {
- if (v instanceof String || v instanceof Number || v instanceof Boolean) {
- String str = v.toString();
- headers.set(key, str);
- } else if (v instanceof byte[]) {
- String str = encodeBase64ASCII((byte[]) v);
- headers.set(key + TripleConstant.HEADER_BIN_SUFFIX, str);
+ if (value instanceof CharSequence || value instanceof Number || value instanceof Boolean) {
+ String str = value.toString();
+ consumer.accept(key, str);
+ } else if (value instanceof Date) {
+ consumer.accept(key, DateFormatter.format((Date) value));
+ } else if (value instanceof byte[]) {
+ String str = encodeBase64ASCII((byte[]) value);
+ consumer.accept(key + TripleConstant.HEADER_BIN_SUFFIX, str);
} else {
LOGGER.warn(
PROTOCOL_UNSUPPORTED,
"",
"",
"Unsupported attachment k: " + key + " class: "
- + v.getClass().getName());
+ + value.getClass().getName());
}
} catch (Throwable t) {
LOGGER.warn(
PROTOCOL_UNSUPPORTED,
"",
"",
- "Meet exception when convert single attachment key:" + key + " value=" + v,
+ "Meet exception when convert single attachment key:" + key + " value=" + value,
t);
}
}
- private static void convertSingleAttachment(HttpHeaders headers, String key, Object v) {
- try {
- if (v instanceof String || v instanceof Number || v instanceof Boolean) {
- String str = v.toString();
- headers.set(key, str);
- } else if (v instanceof byte[]) {
- String str = encodeBase64ASCII((byte[]) v);
- headers.set(key + TripleConstant.HEADER_BIN_SUFFIX, str);
+ /**
+ * Convert the given map to attachments. Ignore Http2 PseudoHeaderName and internal name.
+ *
+ * @param map The map
+ * @return the attachments
+ */
+ public static Map toAttachments(Map map) {
+ if (CollectionUtils.isEmptyMap(map)) {
+ return Collections.emptyMap();
+ }
+ Map res = new HashMap<>(map.size());
+ for (Map.Entry entry : map.entrySet()) {
+ String key = entry.getKey();
+ if (TripleHeaderEnum.containsExcludeAttachments(key)) {
+ continue;
+ }
+ res.put(key, entry.getValue());
+ }
+ return res;
+ }
+
+ /**
+ * Parse and convert headers to attachments. Ignore Http2 PseudoHeaderName and internal name.
+ *
+ * @param headers the headers
+ * @return the attachments
+ */
+ public static Map toAttachments(HttpHeaders headers) {
+ if (headers == null) {
+ return Collections.emptyMap();
+ }
+
+ Map attachments = CollectionUtils.newHashMap(headers.size());
+ for (Map.Entry> entry : headers.entrySet()) {
+ String key = entry.getKey();
+ String value = CollectionUtils.first(entry.getValue());
+ int len = key.length() - TripleConstant.HEADER_BIN_SUFFIX.length();
+ if (len > 0 && TripleConstant.HEADER_BIN_SUFFIX.equals(key.substring(len))) {
+ try {
+ putAttachment(attachments, key.substring(0, len), value == null ? null : decodeASCIIByte(value));
+ } catch (Exception e) {
+ LOGGER.error(PROTOCOL_FAILED_PARSE, "", "", "Failed to parse response attachment key=" + key, e);
+ }
} else {
- LOGGER.warn(
- PROTOCOL_UNSUPPORTED,
- "",
- "",
- "Unsupported attachment k: " + key + " class: "
- + v.getClass().getName());
+ putAttachment(attachments, key, value);
}
- } catch (Throwable t) {
- LOGGER.warn(
- PROTOCOL_UNSUPPORTED,
- "",
- "",
- "Meet exception when convert single attachment key:" + key + " value=" + v,
- t);
}
+
+ // try converting upper key
+ String converted = headers.getFirst(TripleHeaderEnum.TRI_HEADER_CONVERT.getHeader());
+ if (converted == null) {
+ return attachments;
+ }
+ String json = TriRpcStatus.decodeMessage(converted);
+ Map map = JsonUtils.toJavaObject(json, Map.class);
+ for (Map.Entry entry : map.entrySet()) {
+ String key = entry.getKey();
+ Object value = attachments.remove(key);
+ if (value != null) {
+ putAttachment(attachments, key, value);
+ }
+ }
+ return attachments;
+ }
+
+ /**
+ * Put a KV pairs into attachments.
+ *
+ * @param attachments the map to which the attachment will be added
+ * @param key the key of the header
+ * @param value the value of the header
+ */
+ private static void putAttachment(Map attachments, String key, Object value) {
+ if (TripleHeaderEnum.containsExcludeAttachments(key)) {
+ return;
+ }
+ attachments.put(key, value);
}
}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleServerStream.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleServerStream.java
deleted file mode 100644
index 0aaca484910f..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleServerStream.java
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.stream;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.constants.CommonConstants;
-import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.rpc.HeaderFilter;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.PathResolver;
-import org.apache.dubbo.rpc.TriRpcStatus;
-import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils;
-import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
-import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
-import org.apache.dubbo.rpc.protocol.tri.TripleProtocol;
-import org.apache.dubbo.rpc.protocol.tri.call.ReflectionAbstractServerCall;
-import org.apache.dubbo.rpc.protocol.tri.call.StubAbstractServerCall;
-import org.apache.dubbo.rpc.protocol.tri.command.CancelQueueCommand;
-import org.apache.dubbo.rpc.protocol.tri.command.DataQueueCommand;
-import org.apache.dubbo.rpc.protocol.tri.command.HeaderQueueCommand;
-import org.apache.dubbo.rpc.protocol.tri.command.TextDataQueueCommand;
-import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor;
-import org.apache.dubbo.rpc.protocol.tri.compressor.Identity;
-import org.apache.dubbo.rpc.protocol.tri.frame.Deframer;
-import org.apache.dubbo.rpc.protocol.tri.frame.TriDecoder;
-import org.apache.dubbo.rpc.protocol.tri.transport.AbstractH2TransportListener;
-import org.apache.dubbo.rpc.protocol.tri.transport.H2TransportListener;
-import org.apache.dubbo.rpc.protocol.tri.transport.TripleWriteQueue;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.Executor;
-
-import com.google.protobuf.Any;
-import com.google.rpc.DebugInfo;
-import com.google.rpc.Status;
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelFuture;
-import io.netty.handler.codec.http.HttpHeaderNames;
-import io.netty.handler.codec.http.HttpMethod;
-import io.netty.handler.codec.http.HttpResponseStatus;
-import io.netty.handler.codec.http.HttpUtil;
-import io.netty.handler.codec.http2.DefaultHttp2Headers;
-import io.netty.handler.codec.http2.Http2Error;
-import io.netty.handler.codec.http2.Http2Headers;
-import io.netty.handler.codec.http2.Http2StreamChannel;
-import io.netty.util.ReferenceCountUtil;
-import io.netty.util.concurrent.Future;
-
-import static io.netty.handler.codec.http.HttpResponseStatus.OK;
-import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_REQUEST;
-
-public class TripleServerStream extends AbstractStream implements ServerStream {
-
- private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(TripleServerStream.class);
- public final ServerTransportObserver transportObserver = new ServerTransportObserver();
- private final TripleWriteQueue writeQueue;
- private final PathResolver pathResolver;
- private final List filters;
- private final String acceptEncoding;
- private boolean headerSent;
- private boolean trailersSent;
- private volatile boolean reset;
- private ServerStream.Listener listener;
- private final InetSocketAddress remoteAddress;
- private Deframer deframer;
- private boolean rst = false;
- private final Http2StreamChannel http2StreamChannel;
- private final TripleStreamChannelFuture tripleStreamChannelFuture;
-
- public TripleServerStream(
- Http2StreamChannel channel,
- FrameworkModel frameworkModel,
- Executor executor,
- PathResolver pathResolver,
- String acceptEncoding,
- List filters,
- TripleWriteQueue writeQueue) {
- super(executor, frameworkModel);
- this.pathResolver = pathResolver;
- this.acceptEncoding = acceptEncoding;
- this.filters = filters;
- this.writeQueue = writeQueue;
- this.remoteAddress = (InetSocketAddress) channel.remoteAddress();
- this.http2StreamChannel = channel;
- this.tripleStreamChannelFuture = new TripleStreamChannelFuture(channel);
- }
-
- @Override
- public SocketAddress remoteAddress() {
- return remoteAddress;
- }
-
- @Override
- public void request(int n) {
- deframer.request(n);
- }
-
- public ChannelFuture reset(Http2Error cause) {
- ChannelFuture checkResult = preCheck();
- if (!checkResult.isSuccess()) {
- return checkResult;
- }
- this.rst = true;
- return writeQueue.enqueue(CancelQueueCommand.createCommand(tripleStreamChannelFuture, cause));
- }
-
- @Override
- public ChannelFuture sendHeader(Http2Headers headers) {
- if (reset) {
- return http2StreamChannel.newFailedFuture(
- new IllegalStateException("Stream already reset, no more headers allowed"));
- }
- if (headerSent) {
- return http2StreamChannel.newFailedFuture(new IllegalStateException("Header already sent"));
- }
- if (trailersSent) {
- return http2StreamChannel.newFailedFuture(new IllegalStateException("Trailers already sent"));
- }
- ChannelFuture checkResult = preCheck();
- if (!checkResult.isSuccess()) {
- return checkResult;
- }
- headerSent = true;
- return writeQueue
- .enqueue(HeaderQueueCommand.createHeaders(tripleStreamChannelFuture, headers, false))
- .addListener(f -> {
- if (!f.isSuccess()) {
- reset(Http2Error.INTERNAL_ERROR);
- }
- });
- }
-
- @Override
- public Future> cancelByLocal(TriRpcStatus status) {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug(String.format("Cancel stream:%s by local: %s", http2StreamChannel, status));
- }
- return reset(Http2Error.CANCEL);
- }
-
- @Override
- public ChannelFuture complete(
- TriRpcStatus status, Map attachments, boolean isNeedReturnException, int exceptionCode) {
- Http2Headers trailers =
- getTrailers(status, attachments, isNeedReturnException, CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS);
- return sendTrailers(trailers);
- }
-
- private ChannelFuture sendTrailers(Http2Headers trailers) {
- if (reset) {
- return http2StreamChannel.newFailedFuture(
- new IllegalStateException("Stream already reset, no more trailers allowed"));
- }
- if (trailersSent) {
- return http2StreamChannel.newFailedFuture(new IllegalStateException("Trailers already sent"));
- }
- ChannelFuture checkResult = preCheck();
- if (!checkResult.isSuccess()) {
- return checkResult;
- }
- headerSent = true;
- trailersSent = true;
- return writeQueue
- .enqueue(HeaderQueueCommand.createHeaders(tripleStreamChannelFuture, trailers, true))
- .addListener(f -> {
- if (!f.isSuccess()) {
- reset(Http2Error.INTERNAL_ERROR);
- }
- });
- }
-
- private Http2Headers getTrailers(
- TriRpcStatus rpcStatus, Map attachments, boolean isNeedReturnException, int exceptionCode) {
- DefaultHttp2Headers headers = new DefaultHttp2Headers();
- if (!headerSent) {
- headers.status(HttpResponseStatus.OK.codeAsText());
- headers.set(HttpHeaderNames.CONTENT_TYPE, TripleConstant.CONTENT_PROTO);
- }
- StreamUtils.convertAttachment(headers, attachments, TripleProtocol.CONVERT_NO_LOWER_HEADER);
- headers.set(TripleHeaderEnum.STATUS_KEY.getHeader(), String.valueOf(rpcStatus.code.code));
- if (rpcStatus.isOk()) {
- return headers;
- }
- String grpcMessage = getGrpcMessage(rpcStatus);
- grpcMessage = TriRpcStatus.encodeMessage(TriRpcStatus.limitSizeTo1KB(grpcMessage));
- headers.set(TripleHeaderEnum.MESSAGE_KEY.getHeader(), grpcMessage);
- if (!getGrpcStatusDetailEnabled()) {
- return headers;
- }
- Status.Builder builder =
- Status.newBuilder().setCode(rpcStatus.code.code).setMessage(grpcMessage);
- Throwable throwable = rpcStatus.cause;
- if (throwable == null) {
- Status status = builder.build();
- headers.set(
- TripleHeaderEnum.STATUS_DETAIL_KEY.getHeader(),
- StreamUtils.encodeBase64ASCII(status.toByteArray()));
- return headers;
- }
- DebugInfo debugInfo = DebugInfo.newBuilder()
- .addAllStackEntries(ExceptionUtils.getStackFrameList(throwable, 6))
- // can not use now
- // .setDetail(throwable.getMessage())
- .build();
- builder.addDetails(Any.pack(debugInfo));
- Status status = builder.build();
- headers.set(
- TripleHeaderEnum.STATUS_DETAIL_KEY.getHeader(), StreamUtils.encodeBase64ASCII(status.toByteArray()));
- return headers;
- }
-
- private String getGrpcMessage(TriRpcStatus status) {
- if (StringUtils.isNotEmpty(status.description)) {
- return status.description;
- }
- return Optional.ofNullable(status.cause).map(Throwable::getMessage).orElse("unknown");
- }
-
- @Override
- public ChannelFuture sendMessage(byte[] message, int compressFlag) {
- if (reset) {
- return http2StreamChannel.newFailedFuture(
- new IllegalStateException("Stream already reset, no more body allowed"));
- }
- if (!headerSent) {
- return http2StreamChannel.newFailedFuture(
- new IllegalStateException("Headers did not sent before send body"));
- }
- if (trailersSent) {
- return http2StreamChannel.newFailedFuture(
- new IllegalStateException("Trailers already sent, no more body allowed"));
- }
- ChannelFuture checkResult = preCheck();
- if (!checkResult.isSuccess()) {
- return checkResult;
- }
- return writeQueue.enqueue(DataQueueCommand.create(tripleStreamChannelFuture, message, false, compressFlag));
- }
-
- /**
- * Error before create server stream, http plain text will be returned
- *
- * @param code code of error
- * @param status status of error
- */
- private void responsePlainTextError(int code, TriRpcStatus status) {
- ChannelFuture checkResult = preCheck();
- if (!checkResult.isSuccess()) {
- return;
- }
- Http2Headers headers = new DefaultHttp2Headers(true)
- .status(String.valueOf(code))
- .setInt(TripleHeaderEnum.STATUS_KEY.getHeader(), status.code.code)
- .set(TripleHeaderEnum.MESSAGE_KEY.getHeader(), status.description)
- .set(TripleHeaderEnum.CONTENT_TYPE_KEY.getHeader(), TripleConstant.TEXT_PLAIN_UTF8);
- writeQueue.enqueue(HeaderQueueCommand.createHeaders(tripleStreamChannelFuture, headers, false));
- writeQueue.enqueue(TextDataQueueCommand.createCommand(tripleStreamChannelFuture, status.description, true));
- }
-
- /**
- * Error in create stream, unsupported config or triple protocol error. There is no return value
- * because stream will be reset if send trailers failed.
- *
- * @param status status of error
- */
- private void responseErr(TriRpcStatus status) {
- Http2Headers trailers = new DefaultHttp2Headers()
- .status(OK.codeAsText())
- .set(HttpHeaderNames.CONTENT_TYPE, TripleConstant.CONTENT_PROTO)
- .setInt(TripleHeaderEnum.STATUS_KEY.getHeader(), status.code.code)
- .set(TripleHeaderEnum.MESSAGE_KEY.getHeader(), status.toEncodedMessage());
- sendTrailers(trailers);
- }
-
- private Invoker> getInvoker(Http2Headers headers, String serviceName) {
- final String version = headers.contains(TripleHeaderEnum.SERVICE_VERSION.getHeader())
- ? headers.get(TripleHeaderEnum.SERVICE_VERSION.getHeader()).toString()
- : null;
- final String group = headers.contains(TripleHeaderEnum.SERVICE_GROUP.getHeader())
- ? headers.get(TripleHeaderEnum.SERVICE_GROUP.getHeader()).toString()
- : null;
- final String key = URL.buildKey(serviceName, group, version);
- Invoker> invoker = pathResolver.resolve(key);
- if (invoker == null && TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
- invoker = pathResolver.resolve(URL.buildKey(serviceName, group, "1.0.0"));
- }
- if (invoker == null && TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
- invoker = pathResolver.resolve(serviceName);
- }
- return invoker;
- }
-
- private ChannelFuture preCheck() {
- if (!http2StreamChannel.isActive()) {
- return http2StreamChannel.newFailedFuture(new IOException("stream channel is closed"));
- }
- if (rst) {
- return http2StreamChannel.newFailedFuture(new IOException("stream channel has reset"));
- }
- return http2StreamChannel.newSucceededFuture();
- }
-
- public class ServerTransportObserver extends AbstractH2TransportListener implements H2TransportListener {
-
- /**
- * must starts from application/grpc
- */
- private boolean supportContentType(String contentType) {
- if (contentType == null) {
- return false;
- }
- return contentType.startsWith(TripleConstant.APPLICATION_GRPC);
- }
-
- @Override
- public void onHeader(Http2Headers headers, boolean endStream) {
- executor.execute(() -> processHeader(headers, endStream));
- }
-
- private void processHeader(Http2Headers headers, boolean endStream) {
- if (!HttpMethod.POST.asciiName().contentEquals(headers.method())) {
- responsePlainTextError(
- HttpResponseStatus.METHOD_NOT_ALLOWED.code(),
- TriRpcStatus.INTERNAL.withDescription(
- String.format("Method '%s' is not supported", headers.method())));
- return;
- }
-
- if (headers.path() == null) {
- responsePlainTextError(
- HttpResponseStatus.NOT_FOUND.code(),
- TriRpcStatus.fromCode(TriRpcStatus.Code.UNIMPLEMENTED.code)
- .withDescription("Expected path but is missing"));
- return;
- }
-
- final String path = headers.path().toString();
- if (path.charAt(0) != '/') {
- responsePlainTextError(
- HttpResponseStatus.NOT_FOUND.code(),
- TriRpcStatus.fromCode(TriRpcStatus.Code.UNIMPLEMENTED.code)
- .withDescription(String.format("Expected path to start with /: %s", path)));
- return;
- }
-
- final CharSequence contentType = HttpUtil.getMimeType(headers.get(HttpHeaderNames.CONTENT_TYPE));
- if (contentType == null) {
- responsePlainTextError(
- HttpResponseStatus.UNSUPPORTED_MEDIA_TYPE.code(),
- TriRpcStatus.fromCode(TriRpcStatus.Code.INTERNAL.code)
- .withDescription("Content-Type is missing from the request"));
- return;
- }
-
- final String contentString = contentType.toString();
- if (!supportContentType(contentString)) {
- responsePlainTextError(
- HttpResponseStatus.UNSUPPORTED_MEDIA_TYPE.code(),
- TriRpcStatus.fromCode(TriRpcStatus.Code.INTERNAL.code)
- .withDescription(String.format("Content-Type '%s' is not supported", contentString)));
- return;
- }
-
- String[] parts = path.split("/");
- if (parts.length != 3) {
- responseErr(TriRpcStatus.UNIMPLEMENTED.withDescription("Bad path format:" + path));
- return;
- }
- String serviceName = parts[1];
- String originalMethodName = parts[2];
-
- Invoker> invoker = getInvoker(headers, serviceName);
- if (invoker == null) {
- responseErr(TriRpcStatus.UNIMPLEMENTED.withDescription("Service not found:" + serviceName));
- return;
- }
-
- if (endStream) {
- return;
- }
-
- DeCompressor deCompressor = DeCompressor.NONE;
- CharSequence messageEncoding = headers.get(TripleHeaderEnum.GRPC_ENCODING.getHeader());
- if (null != messageEncoding) {
- String compressorStr = messageEncoding.toString();
- if (!Identity.MESSAGE_ENCODING.equals(compressorStr)) {
- DeCompressor compressor = DeCompressor.getCompressor(frameworkModel, compressorStr);
- if (null == compressor) {
- responseErr(TriRpcStatus.fromCode(TriRpcStatus.Code.UNIMPLEMENTED.code)
- .withDescription(String.format("Grpc-encoding '%s' is not supported", compressorStr)));
- return;
- }
- deCompressor = compressor;
- }
- }
-
- Map requestMetadata = headersToMap(
- headers, () -> Optional.ofNullable(headers.get(TripleHeaderEnum.TRI_HEADER_CONVERT.getHeader()))
- .map(CharSequence::toString)
- .orElse(null));
- boolean hasStub = pathResolver.hasNativeStub(path);
- if (hasStub) {
- listener = new StubAbstractServerCall(
- invoker,
- TripleServerStream.this,
- frameworkModel,
- acceptEncoding,
- serviceName,
- originalMethodName,
- executor);
- } else {
- listener = new ReflectionAbstractServerCall(
- invoker,
- TripleServerStream.this,
- frameworkModel,
- acceptEncoding,
- serviceName,
- originalMethodName,
- filters,
- executor);
- }
- // must before onHeader
- deframer = new TriDecoder(deCompressor, new ServerDecoderListener(listener));
- listener.onHeader(requestMetadata);
- }
-
- @Override
- public void onData(ByteBuf data, boolean endStream) {
- try {
- executor.execute(() -> doOnData(data, endStream));
- } catch (Throwable t) {
- // Tasks will be rejected when the thread pool is closed or full,
- // ByteBuf needs to be released to avoid out of heap memory leakage.
- // For example, ThreadLessExecutor will be shutdown when request timeout {@link AsyncRpcResult}
- ReferenceCountUtil.release(data);
- LOGGER.error(PROTOCOL_FAILED_REQUEST, "", "", "submit onData task failed", t);
- }
- }
-
- private void doOnData(ByteBuf data, boolean endStream) {
- if (deframer == null) {
- return;
- }
- deframer.deframe(data);
- if (endStream) {
- deframer.close();
- }
- }
-
- @Override
- public void cancelByRemote(long errorCode) {
- TripleServerStream.this.reset = true;
- if (!trailersSent) {
- // send rst if stream not closed
- reset(Http2Error.valueOf(errorCode));
- }
- if (listener == null) {
- return;
- }
- executor.execute(() -> listener.onCancelByRemote(
- TriRpcStatus.CANCELLED.withDescription("Canceled by client ,errorCode=" + errorCode)));
- }
- }
-
- private static class ServerDecoderListener implements TriDecoder.Listener {
-
- private final ServerStream.Listener listener;
-
- public ServerDecoderListener(ServerStream.Listener listener) {
- this.listener = listener;
- }
-
- @Override
- public void onRawMessage(byte[] data) {
- listener.onMessage(data, false);
- }
-
- @Override
- public void close() {
- listener.onComplete();
- }
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/AbstractH2TransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/AbstractH2TransportListener.java
index fe5c341b2060..1033ea26cbd0 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/AbstractH2TransportListener.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/AbstractH2TransportListener.java
@@ -56,7 +56,7 @@ protected Map headersToMap(Http2Headers trailers, Supplier TripleConstant.HEADER_BIN_SUFFIX.length()) {
try {
String realKey = key.substring(0, key.length() - TripleConstant.HEADER_BIN_SUFFIX.length());
- byte[] value = StreamUtils.decodeASCIIByte(header.getValue());
+ byte[] value = StreamUtils.decodeASCIIByte(header.getValue().toString());
attachments.put(realKey, value);
} catch (Exception e) {
LOGGER.error(PROTOCOL_FAILED_PARSE, "", "", "Failed to parse response attachment key=" + key, e);
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/TripleHttp2FrameServerHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/TripleHttp2FrameServerHandler.java
deleted file mode 100644
index daebefc3394d..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/TripleHttp2FrameServerHandler.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.transport;
-
-import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.rpc.HeaderFilter;
-import org.apache.dubbo.rpc.PathResolver;
-import org.apache.dubbo.rpc.TriRpcStatus;
-import org.apache.dubbo.rpc.executor.ExecutorSupport;
-import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor;
-import org.apache.dubbo.rpc.protocol.tri.stream.TripleServerStream;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-import io.netty.channel.ChannelDuplexHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http2.Http2DataFrame;
-import io.netty.handler.codec.http2.Http2HeadersFrame;
-import io.netty.handler.codec.http2.Http2ResetFrame;
-import io.netty.handler.codec.http2.Http2StreamChannel;
-import io.netty.util.ReferenceCountUtil;
-import io.netty.util.ReferenceCounted;
-
-import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_RESPONSE;
-
-public class TripleHttp2FrameServerHandler extends ChannelDuplexHandler {
-
- private static final ErrorTypeAwareLogger LOGGER =
- LoggerFactory.getErrorTypeAwareLogger(TripleHttp2FrameServerHandler.class);
- private final PathResolver pathResolver;
- private final ExecutorSupport executorSupport;
- private final String acceptEncoding;
- private final TripleServerStream tripleServerStream;
-
- public TripleHttp2FrameServerHandler(
- FrameworkModel frameworkModel,
- ExecutorSupport executorSupport,
- List filters,
- Http2StreamChannel channel,
- TripleWriteQueue writeQueue) {
- this.executorSupport = executorSupport;
- this.acceptEncoding = String.join(
- ",", frameworkModel.getExtensionLoader(DeCompressor.class).getSupportedExtensions());
- this.pathResolver =
- frameworkModel.getExtensionLoader(PathResolver.class).getDefaultExtension();
- // The executor will be assigned in onHeadersRead method
- tripleServerStream = new TripleServerStream(
- channel, frameworkModel, null, pathResolver, acceptEncoding, filters, writeQueue);
- }
-
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- if (msg instanceof Http2HeadersFrame) {
- onHeadersRead(ctx, (Http2HeadersFrame) msg);
- } else if (msg instanceof Http2DataFrame) {
- onDataRead(ctx, (Http2DataFrame) msg);
- } else if (msg instanceof ReferenceCounted) {
- // ignored
- ReferenceCountUtil.release(msg);
- }
- }
-
- @Override
- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
- if (evt instanceof Http2ResetFrame) {
- onResetRead(ctx, (Http2ResetFrame) evt);
- } else {
- super.userEventTriggered(ctx, evt);
- }
- }
-
- public void onResetRead(ChannelHandlerContext ctx, Http2ResetFrame frame) {
- LOGGER.warn(
- PROTOCOL_FAILED_RESPONSE, "", "", "Triple Server received remote reset errorCode=" + frame.errorCode());
- if (tripleServerStream != null) {
- tripleServerStream.transportObserver.cancelByRemote(frame.errorCode());
- }
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- if (LOGGER.isWarnEnabled()) {
- LOGGER.warn(PROTOCOL_FAILED_RESPONSE, "", "", "Exception in processing triple message", cause);
- }
- TriRpcStatus status = TriRpcStatus.getStatus(cause, "Provider's error:\n" + cause.getMessage());
- tripleServerStream.cancelByLocal(status);
- }
-
- public void onDataRead(ChannelHandlerContext ctx, Http2DataFrame msg) throws Exception {
- tripleServerStream.transportObserver.onData(msg.content(), msg.isEndStream());
- }
-
- public void onHeadersRead(ChannelHandlerContext ctx, Http2HeadersFrame msg) throws Exception {
- Executor executor = executorSupport.getExecutor(msg.headers());
- tripleServerStream.setExecutor(executor);
- tripleServerStream.transportObserver.onHeader(msg.headers(), msg.isEndStream());
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/call/ReflectionServerCallTest.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/call/ReflectionServerCallTest.java
deleted file mode 100644
index c598305ce62d..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/call/ReflectionServerCallTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.model.MethodDescriptor;
-import org.apache.dubbo.rpc.model.ProviderModel;
-import org.apache.dubbo.rpc.model.ReflectionMethodDescriptor;
-import org.apache.dubbo.rpc.model.ServiceDescriptor;
-import org.apache.dubbo.rpc.model.ServiceMetadata;
-import org.apache.dubbo.rpc.protocol.tri.DescriptorService;
-import org.apache.dubbo.rpc.protocol.tri.HelloReply;
-import org.apache.dubbo.rpc.protocol.tri.stream.TripleServerStream;
-
-import java.lang.reflect.Method;
-import java.util.Collections;
-
-import io.netty.util.concurrent.ImmediateEventExecutor;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-
-import static org.junit.jupiter.api.Assertions.fail;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
-
-class ReflectionServerCallTest {
-
- @Test
- void doStartCall() throws NoSuchMethodException {
- Invoker> invoker = Mockito.mock(Invoker.class);
- TripleServerStream serverStream = Mockito.mock(TripleServerStream.class);
- ProviderModel providerModel = Mockito.mock(ProviderModel.class);
- ServiceMetadata serviceMetadata = new ServiceMetadata();
- Method method = DescriptorService.class.getMethod("sayHello", HelloReply.class);
- MethodDescriptor methodDescriptor = new ReflectionMethodDescriptor(method);
- URL url = Mockito.mock(URL.class);
- when(invoker.getUrl()).thenReturn(url);
- when(url.getServiceModel()).thenReturn(providerModel);
- when(providerModel.getServiceMetadata()).thenReturn(serviceMetadata);
-
- String service = "testService";
- String methodName = "method";
- try {
- ReflectionAbstractServerCall call = new ReflectionAbstractServerCall(
- invoker,
- serverStream,
- new FrameworkModel(),
- "",
- service,
- methodName,
- Collections.emptyList(),
- ImmediateEventExecutor.INSTANCE);
- fail();
- } catch (Exception e) {
- // pass
- }
-
- ServiceDescriptor serviceDescriptor = Mockito.mock(ServiceDescriptor.class);
- when(serviceDescriptor.getMethods(anyString())).thenReturn(Collections.singletonList(methodDescriptor));
-
- when(providerModel.getServiceModel()).thenReturn(serviceDescriptor);
-
- ReflectionAbstractServerCall call2 = new ReflectionAbstractServerCall(
- invoker,
- serverStream,
- new FrameworkModel(),
- "",
- service,
- methodName,
- Collections.emptyList(),
- ImmediateEventExecutor.INSTANCE);
- call2.onHeader(Collections.emptyMap());
- call2.onMessage(new byte[0], false);
- call2.onComplete();
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/call/StubServerCallTest.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/call/StubServerCallTest.java
deleted file mode 100644
index b500e91bbc55..000000000000
--- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/call/StubServerCallTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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 org.apache.dubbo.rpc.protocol.tri.call;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.model.MethodDescriptor.RpcType;
-import org.apache.dubbo.rpc.model.ProviderModel;
-import org.apache.dubbo.rpc.model.ServiceDescriptor;
-import org.apache.dubbo.rpc.model.StubMethodDescriptor;
-import org.apache.dubbo.rpc.protocol.tri.stream.TripleServerStream;
-
-import java.util.Collections;
-
-import io.netty.util.concurrent.ImmediateEventExecutor;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
-
-class StubServerCallTest {
-
- @Test
- void doStartCall() throws Exception {
- Invoker> invoker = Mockito.mock(Invoker.class);
- TripleServerStream tripleServerStream = Mockito.mock(TripleServerStream.class);
- ProviderModel providerModel = Mockito.mock(ProviderModel.class);
- ServiceDescriptor serviceDescriptor = Mockito.mock(ServiceDescriptor.class);
- StubMethodDescriptor methodDescriptor = Mockito.mock(StubMethodDescriptor.class);
- URL url = Mockito.mock(URL.class);
- when(invoker.getUrl()).thenReturn(url);
- when(url.getServiceModel()).thenReturn(providerModel);
- when(providerModel.getServiceModel()).thenReturn(serviceDescriptor);
- when(serviceDescriptor.getMethods(anyString())).thenReturn(Collections.singletonList(methodDescriptor));
- when(methodDescriptor.getRpcType()).thenReturn(RpcType.UNARY);
- when(methodDescriptor.parseRequest(any(byte[].class))).thenReturn("test");
- String service = "testService";
- String method = "method";
- StubAbstractServerCall call = new StubAbstractServerCall(
- invoker,
- tripleServerStream,
- new FrameworkModel(),
- "",
- service,
- method,
- ImmediateEventExecutor.INSTANCE);
- call.onHeader(Collections.emptyMap());
- call.onMessage(new byte[0], false);
- call.onComplete();
- }
-}
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/StreamUtilsTest.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/StreamUtilsTest.java
index 07d08513e0e5..fc79f4c683c9 100644
--- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/StreamUtilsTest.java
+++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/StreamUtilsTest.java
@@ -55,7 +55,7 @@ void testConvertAttachment() throws InterruptedException {
attachments.put("Upper", "Upper");
attachments.put("obj", new Object());
- StreamUtils.convertAttachment(headers, attachments, false);
+ StreamUtils.putHeaders(headers, attachments, false);
Assertions.assertNull(headers.get(TripleHeaderEnum.PATH_KEY.getHeader()));
Assertions.assertNull(headers.get("Upper"));
Assertions.assertNull(headers.get("obj"));
@@ -63,7 +63,7 @@ void testConvertAttachment() throws InterruptedException {
headers = new DefaultHttp2Headers();
headers.add("key", "value");
- StreamUtils.convertAttachment(headers, attachments, true);
+ StreamUtils.putHeaders(headers, attachments, true);
Assertions.assertNull(headers.get(TripleHeaderEnum.PATH_KEY.getHeader()));
Assertions.assertNull(headers.get("Upper"));
Assertions.assertNull(headers.get("obj"));
@@ -89,7 +89,7 @@ void testConvertAttachment() throws InterruptedException {
executorService.execute(() -> {
DefaultHttp2Headers headers2 = new DefaultHttp2Headers();
headers2.add("key", "value");
- StreamUtils.convertAttachment(headers2, attachments2, true);
+ StreamUtils.putHeaders(headers2, attachments2, true);
if (headers2.get(TripleHeaderEnum.PATH_KEY.getHeader()) != null) {
return;