diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TypeUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TypeUtils.java index 7035f004a267..01da5f5dd919 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TypeUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TypeUtils.java @@ -235,4 +235,8 @@ static Class getArgumentClass(Type type, int index) { } return null; } + + static Class getSuperGenericType(Class clazz, Class interfaceClass, int index) { + return findActualTypeArgument(clazz, interfaceClass, index); + } } diff --git a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/ServletStreamChannel.java b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/ServletStreamChannel.java index af1e12a906ed..456bff0c04de 100644 --- a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/ServletStreamChannel.java +++ b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/ServletStreamChannel.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.remoting.http12.EmptyOutputStreamMessage; import org.apache.dubbo.remoting.http12.HttpConstants; import org.apache.dubbo.remoting.http12.HttpHeaderNames; import org.apache.dubbo.remoting.http12.HttpHeaders; @@ -38,6 +39,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; +import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.HashMap; @@ -48,7 +50,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; -final class ServletStreamChannel implements H2StreamChannel { +final class ServletStreamChannel implements H2StreamChannel { private static final Logger LOGGER = LoggerFactory.getLogger(ServletStreamChannel.class); @@ -104,6 +106,7 @@ public void onWritePossible() { } } + @SuppressWarnings("unchecked") private void flushQueue() { if (writeQueue.isEmpty()) { return; @@ -114,7 +117,7 @@ private void flushQueue() { if (obj instanceof HttpMetadata) { writeHeaderInternal((HttpMetadata) obj); } else if (obj instanceof HttpOutputMessage) { - writeMessageInternal((HttpOutputMessage) obj); + writeMessageInternal((HttpOutputMessage) obj); } } } @@ -150,8 +153,8 @@ public CompletableFuture writeResetFrame(long errorCode) { } @Override - public Http2OutputMessage newOutputMessage(boolean endStream) { - return new Http2OutputMessageFrame(new ByteArrayOutputStream(256), endStream); + public Http2OutputMessage newOutputMessage(boolean endStream) { + return new Http2OutputMessageFrame<>(new ByteArrayOutputStream(256), endStream); } @Override @@ -213,7 +216,7 @@ private void writeHeaderInternal(HttpMetadata httpMetadata) { } @Override - public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { if (writeable.get()) { flushQueue(); writeMessageInternal(httpOutputMessage); @@ -223,11 +226,11 @@ public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) return completed(); } - private void writeMessageInternal(HttpOutputMessage httpOutputMessage) { + private void writeMessageInternal(HttpOutputMessage httpOutputMessage) { boolean endStream = false; if (httpOutputMessage instanceof Http2OutputMessage) { - endStream = ((Http2OutputMessage) httpOutputMessage).isEndStream(); - } else if (httpOutputMessage == HttpOutputMessage.EMPTY_MESSAGE) { + endStream = ((Http2OutputMessage) httpOutputMessage).isEndStream(); + } else if (httpOutputMessage == EmptyOutputStreamMessage.INSTANCE) { endStream = true; } try { diff --git a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java index 749063dcc79e..404132502a3a 100644 --- a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java +++ b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.remoting.http12.HttpVersion; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h1.Http1InputMessage; import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener; import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame; @@ -56,6 +57,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Arrays; import java.util.Set; @@ -101,8 +104,13 @@ private void handleHttp2(HttpServletRequest request, HttpServletResponse respons AsyncContext context = request.startAsync(request, response); ServletStreamChannel channel = new ServletStreamChannel(request, response, context); try { - Http2TransportListener listener = determineHttp2ServerTransportListenerFactory(request.getContentType()) - .newInstance(channel, ServletExchanger.getUrl(), FrameworkModel.defaultModel()); + Http2TransportListener listener = determineHttp2ServerTransportListenerFactory( + request.getContentType()) + .newInstance( + channel, + ServletExchanger.getUrl(), + FrameworkModel.defaultModel(), + new MessageTypeToken() {}); boolean isGrpc = listener instanceof GrpcHttp2ServerTransportListener; channel.setGrpc(isGrpc); @@ -123,15 +131,19 @@ private void handleHttp1(HttpServletRequest request, HttpServletResponse respons AsyncContext context = request.startAsync(request, response); ServletStreamChannel channel = new ServletStreamChannel(request, response, context); try { - Http1ServerTransportListener listener = DefaultHttp11ServerTransportListenerFactory.INSTANCE.newInstance( - channel, ServletExchanger.getUrl(), FrameworkModel.defaultModel()); + Http1ServerTransportListener listener = + DefaultHttp11ServerTransportListenerFactory.INSTANCE.newInstance( + channel, + ServletExchanger.getUrl(), + FrameworkModel.defaultModel(), + new MessageTypeToken() {}); channel.setGrpc(false); context.setTimeout(resolveTimeout(request, false)); ServletInputStream is = request.getInputStream(); response.getOutputStream().setWriteListener(new TripleWriteListener(channel)); listener.onMetadata(new HttpMetadataAdapter(request)); - listener.onData(new Http1InputMessage( + listener.onData(new Http1InputMessage<>( is.available() == 0 ? StreamUtils.EMPTY : new ByteArrayInputStream(StreamUtils.readBytes(is)))); } catch (Throwable t) { LOGGER.info("Failed to process request", t); @@ -221,12 +233,15 @@ public void onStartAsync(AsyncEvent event) {} private static final class TripleReadListener implements ReadListener { - private final Http2TransportListener listener; + private final Http2TransportListener listener; private final ServletStreamChannel channel; private final ServletInputStream input; private final byte[] buffer = new byte[4 * 1024]; - TripleReadListener(Http2TransportListener listener, ServletStreamChannel channel, ServletInputStream input) { + TripleReadListener( + Http2TransportListener listener, + ServletStreamChannel channel, + ServletInputStream input) { this.listener = listener; this.channel = channel; this.input = input; @@ -240,13 +255,13 @@ public void onDataAvailable() throws IOException { return; } byte[] copy = Arrays.copyOf(buffer, length); - listener.onData(new Http2InputMessageFrame(new ByteArrayInputStream(copy), false)); + listener.onData(new Http2InputMessageFrame<>(new ByteArrayInputStream(copy), false)); } } @Override public void onAllDataRead() { - listener.onData(new Http2InputMessageFrame(StreamUtils.EMPTY, true)); + listener.onData(new Http2InputMessageFrame<>(StreamUtils.EMPTY, true)); } @Override diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleBinaryMessageHandler.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleBinaryMessageHandler.java index a507f6f1e421..b719a2b85e07 100644 --- a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleBinaryMessageHandler.java +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleBinaryMessageHandler.java @@ -23,20 +23,23 @@ import javax.websocket.MessageHandler; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.ByteBuffer; public class TripleBinaryMessageHandler implements MessageHandler.Partial { - private final WebSocketTransportListener webSocketTransportListener; + private final WebSocketTransportListener webSocketTransportListener; - public TripleBinaryMessageHandler(WebSocketTransportListener webSocketTransportListener) { + public TripleBinaryMessageHandler( + WebSocketTransportListener webSocketTransportListener) { this.webSocketTransportListener = webSocketTransportListener; } @Override public void onMessage(ByteBuffer messagePart, boolean last) { - Http2InputMessage http2InputMessage = - new Http2InputMessageFrame(new FinalFragmentByteArrayInputStream(messagePart.array(), last), false); + Http2InputMessage http2InputMessage = + new Http2InputMessageFrame<>(new FinalFragmentByteArrayInputStream(messagePart.array(), last), false); webSocketTransportListener.onData(http2InputMessage); } } diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleEndpoint.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleEndpoint.java index 54eb85fb6be8..ffe75863817b 100644 --- a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleEndpoint.java +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleEndpoint.java @@ -24,6 +24,7 @@ import org.apache.dubbo.remoting.http12.HttpHeaders; import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.Http2Header; import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame; @@ -39,6 +40,9 @@ import javax.websocket.EndpointConfig; import javax.websocket.Session; +import java.io.InputStream; +import java.io.OutputStream; + import static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_LISTENER; public class TripleEndpoint extends Endpoint { @@ -55,36 +59,43 @@ public void onOpen(Session session, EndpointConfig config) { TripleConfig tripleConfig = ConfigManager.getProtocolOrDefault(url).getTripleOrDefault(); WebSocketStreamChannel webSocketStreamChannel = new WebSocketStreamChannel(session, tripleConfig); - WebSocketTransportListener webSocketTransportListener = + WebSocketTransportListener webSocketTransportListener = DefaultWebSocketServerTransportListenerFactory.INSTANCE.newInstance( - webSocketStreamChannel, url, FrameworkModel.defaultModel()); + webSocketStreamChannel, + url, + FrameworkModel.defaultModel(), + new MessageTypeToken() {}); webSocketTransportListener.onMetadata(http2Header); session.addMessageHandler(new TripleTextMessageHandler(webSocketTransportListener)); session.addMessageHandler(new TripleBinaryMessageHandler(webSocketTransportListener)); session.getUserProperties().put(TRIPLE_WEBSOCKET_LISTENER, webSocketTransportListener); } + @SuppressWarnings("unchecked") @Override public void onClose(Session session, CloseReason closeReason) { super.onClose(session, closeReason); - WebSocketTransportListener webSocketTransportListener = - (WebSocketTransportListener) session.getUserProperties().get(TRIPLE_WEBSOCKET_LISTENER); + WebSocketTransportListener webSocketTransportListener = + (WebSocketTransportListener) + session.getUserProperties().get(TRIPLE_WEBSOCKET_LISTENER); if (webSocketTransportListener == null) { return; } if (closeReason.getCloseCode().getCode() == CloseCodes.NORMAL_CLOSURE.getCode()) { - Http2InputMessage http2InputMessage = new Http2InputMessageFrame(StreamUtils.EMPTY, true); + Http2InputMessage http2InputMessage = new Http2InputMessageFrame<>(StreamUtils.EMPTY, true); webSocketTransportListener.onData(http2InputMessage); return; } webSocketTransportListener.cancelByRemote(closeReason.getCloseCode().getCode()); } + @SuppressWarnings("unchecked") @Override public void onError(Session session, Throwable thr) { super.onError(session, thr); - WebSocketTransportListener webSocketTransportListener = - (WebSocketTransportListener) session.getUserProperties().get(TRIPLE_WEBSOCKET_LISTENER); + WebSocketTransportListener webSocketTransportListener = + (WebSocketTransportListener) + session.getUserProperties().get(TRIPLE_WEBSOCKET_LISTENER); if (webSocketTransportListener == null) { return; } diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleTextMessageHandler.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleTextMessageHandler.java index 6ac96afde133..dae408b36987 100644 --- a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleTextMessageHandler.java +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleTextMessageHandler.java @@ -23,19 +23,21 @@ import javax.websocket.MessageHandler; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; public class TripleTextMessageHandler implements MessageHandler.Partial { - private final WebSocketTransportListener webSocketTransportListener; + private final WebSocketTransportListener webSocketTransportListener; - public TripleTextMessageHandler(WebSocketTransportListener webSocketTransportListener) { + public TripleTextMessageHandler(WebSocketTransportListener webSocketTransportListener) { this.webSocketTransportListener = webSocketTransportListener; } @Override public void onMessage(String messagePart, boolean last) { - Http2InputMessage http2InputMessage = new Http2InputMessageFrame( + Http2InputMessage http2InputMessage = new Http2InputMessageFrame<>( new FinalFragmentByteArrayInputStream(messagePart.getBytes(StandardCharsets.UTF_8), last), false); webSocketTransportListener.onData(http2InputMessage); } diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketStreamChannel.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketStreamChannel.java index a92235883a63..57a347854b1e 100644 --- a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketStreamChannel.java +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketStreamChannel.java @@ -35,6 +35,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; @@ -44,7 +45,7 @@ import static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_REMOTE_ADDRESS; -public class WebSocketStreamChannel implements H2StreamChannel { +public class WebSocketStreamChannel implements H2StreamChannel { private final Session session; @@ -78,8 +79,8 @@ public CompletableFuture writeResetFrame(long errorCode) { } @Override - public Http2OutputMessage newOutputMessage(boolean endStream) { - return new Http2OutputMessageFrame( + public Http2OutputMessage newOutputMessage(boolean endStream) { + return new Http2OutputMessageFrame<>( new LimitedByteArrayOutputStream(256, tripleConfig.getMaxResponseBodySizeOrDefault()), endStream); } @@ -99,7 +100,7 @@ public CompletableFuture writeHeader(HttpMetadata httpMetadata) { } @Override - public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { ByteArrayOutputStream body = (ByteArrayOutputStream) httpOutputMessage.getBody(); CompletableFuture completableFuture = new CompletableFuture<>(); try { diff --git a/dubbo-remoting/dubbo-remoting-http12/pom.xml b/dubbo-remoting/dubbo-remoting-http12/pom.xml index 4d16603471c6..bc3d12fe2504 100644 --- a/dubbo-remoting/dubbo-remoting-http12/pom.xml +++ b/dubbo-remoting/dubbo-remoting-http12/pom.xml @@ -56,6 +56,12 @@ netty-codec-http2 + + org.apache.fory + fory-core + 0.12.0 + + com.google.protobuf protobuf-java-util diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/frame/RecordListener.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/EmptyInputStreamMessage.java similarity index 71% rename from dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/frame/RecordListener.java rename to dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/EmptyInputStreamMessage.java index c9ec2776d233..843c0b59e068 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/frame/RecordListener.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/EmptyInputStreamMessage.java @@ -14,21 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.frame; +package org.apache.dubbo.remoting.http12; -public class RecordListener implements TriDecoder.Listener { - byte[] lastData; - int dataCount; - boolean close; +import org.apache.dubbo.common.io.StreamUtils; - @Override - public void onRawMessage(byte[] data) { - dataCount += 1; - lastData = data; - } +import java.io.InputStream; + +public class EmptyInputStreamMessage implements HttpInputMessage { + + public static final EmptyInputStreamMessage INSTANCE = new EmptyInputStreamMessage(); @Override - public void close() { - close = true; + public InputStream getBody() { + return StreamUtils.EMPTY; } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/EmptyOutputStreamMessage.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/EmptyOutputStreamMessage.java new file mode 100644 index 000000000000..a8746051d495 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/EmptyOutputStreamMessage.java @@ -0,0 +1,32 @@ +/* + * 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.ByteArrayOutputStream; +import java.io.OutputStream; + +public class EmptyOutputStreamMessage implements HttpOutputMessage { + + public static final EmptyOutputStreamMessage INSTANCE = new EmptyOutputStreamMessage(); + + private final OutputStream emptyOutput = new ByteArrayOutputStream(0); + + @Override + public OutputStream getBody() { + return emptyOutput; + } +} 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 67c2a1cfebb9..5759716992f5 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 @@ -19,13 +19,13 @@ import java.net.SocketAddress; import java.util.concurrent.CompletableFuture; -public interface HttpChannel { +public interface HttpChannel { CompletableFuture writeHeader(HttpMetadata httpMetadata); - CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage); + CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage); - HttpOutputMessage newOutputMessage(); + HttpOutputMessage newOutputMessage(); SocketAddress remoteAddress(); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannelHolder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannelHolder.java index f38149a3b092..f5521e269078 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannelHolder.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannelHolder.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.remoting.http12; -public interface HttpChannelHolder { +public interface HttpChannelHolder { - HttpChannel getHttpChannel(); + HttpChannel getHttpChannel(); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpInputMessage.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpInputMessage.java index 717b03665a05..3e5c2d6adb52 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpInputMessage.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpInputMessage.java @@ -16,15 +16,14 @@ */ package org.apache.dubbo.remoting.http12; -import java.io.IOException; -import java.io.InputStream; +public interface HttpInputMessage extends AutoCloseable { -public interface HttpInputMessage extends AutoCloseable { - - InputStream getBody(); + T getBody(); @Override - default void close() throws IOException { - getBody().close(); + default void close() throws Exception { + if (getBody() instanceof AutoCloseable) { + ((AutoCloseable) getBody()).close(); + } } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpOutputMessage.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpOutputMessage.java index ac64685bd0ab..be27b4bdd2bc 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpOutputMessage.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpOutputMessage.java @@ -16,26 +16,14 @@ */ package org.apache.dubbo.remoting.http12; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; +public interface HttpOutputMessage extends AutoCloseable { -public interface HttpOutputMessage extends AutoCloseable { - - HttpOutputMessage EMPTY_MESSAGE = new HttpOutputMessage() { - - private final OutputStream INPUT_STREAM = new ByteArrayOutputStream(0); - - @Override - public OutputStream getBody() { - return INPUT_STREAM; - } - }; - - OutputStream getBody(); + T getBody(); @Override - default void close() throws IOException { - getBody().close(); + default void close() throws Exception { + if (getBody() instanceof AutoCloseable) { + ((AutoCloseable) getBody()).close(); + } } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpTransportListener.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpTransportListener.java index 9265a3ba93a7..f2bc22756b49 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpTransportListener.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpTransportListener.java @@ -16,7 +16,8 @@ */ package org.apache.dubbo.remoting.http12; -public interface HttpTransportListener
{ +public interface HttpTransportListener< + HEADER extends HttpMetadata, MESSAGE extends HttpInputMessage, INPUT, OUTPUT> { void onMetadata(HEADER metadata); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/MessageTypeToken.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/MessageTypeToken.java new file mode 100644 index 000000000000..fc10b7d3fad4 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/MessageTypeToken.java @@ -0,0 +1,39 @@ +/* + * 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.TypeUtils; + +public abstract class MessageTypeToken { + + private final Class inputType; + private final Class outputType; + + @SuppressWarnings("unchecked") + protected MessageTypeToken() { + this.inputType = (Class) TypeUtils.getSuperGenericType(this.getClass(), 0); + this.outputType = (Class) TypeUtils.getSuperGenericType(this.getClass(), 1); + } + + public Class getInputType() { + return inputType; + } + + public Class getOutputType() { + return outputType; + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/ServerHttpChannelObserver.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/ServerHttpChannelObserver.java index b594f01d7159..f335ed751e8b 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/ServerHttpChannelObserver.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/ServerHttpChannelObserver.java @@ -21,7 +21,8 @@ import java.util.function.BiConsumer; import java.util.function.Function; -public interface ServerHttpChannelObserver extends StreamObserver, AutoCloseable { +public interface ServerHttpChannelObserver, OUTPUT> + extends StreamObserver, AutoCloseable { H getHttpChannel(); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/DataQueueCommand.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/DataQueueCommand.java index d01e58562343..c96b9b5accbb 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/DataQueueCommand.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/DataQueueCommand.java @@ -18,11 +18,11 @@ import org.apache.dubbo.remoting.http12.HttpOutputMessage; -public class DataQueueCommand extends HttpChannelQueueCommand { +public class DataQueueCommand extends HttpChannelQueueCommand { - private final HttpOutputMessage httpOutputMessage; + private final HttpOutputMessage httpOutputMessage; - public DataQueueCommand(HttpOutputMessage httpMessage) { + public DataQueueCommand(HttpOutputMessage httpMessage) { this.httpOutputMessage = httpMessage; } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HeaderQueueCommand.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HeaderQueueCommand.java index cf286bc6c28e..6656c1d61686 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HeaderQueueCommand.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HeaderQueueCommand.java @@ -18,7 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpMetadata; -public class HeaderQueueCommand extends HttpChannelQueueCommand { +public class HeaderQueueCommand extends HttpChannelQueueCommand { private final HttpMetadata httpMetadata; diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpChannelQueueCommand.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpChannelQueueCommand.java index 6474dd814381..38a3d5ff113a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpChannelQueueCommand.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpChannelQueueCommand.java @@ -21,16 +21,16 @@ import java.util.concurrent.CompletableFuture; -public abstract class HttpChannelQueueCommand extends CompletableFuture - implements QueueCommand, HttpChannelHolder { +public abstract class HttpChannelQueueCommand extends CompletableFuture + implements QueueCommand, HttpChannelHolder { - private HttpChannelHolder httpChannelHolder; + private HttpChannelHolder httpChannelHolder; - public void setHttpChannel(HttpChannelHolder httpChannelHolder) { + public void setHttpChannel(HttpChannelHolder httpChannelHolder) { this.httpChannelHolder = httpChannelHolder; } - public HttpChannel getHttpChannel() { + public HttpChannel getHttpChannel() { return httpChannelHolder.getHttpChannel(); } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpWriteQueue.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpWriteQueue.java index f7a04cc0d4ac..87e84ba92ede 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpWriteQueue.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpWriteQueue.java @@ -21,7 +21,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; -public class HttpWriteQueue extends BatchExecutorQueue { +public class HttpWriteQueue extends BatchExecutorQueue> { private final Executor executor; @@ -29,18 +29,18 @@ public HttpWriteQueue(Executor executor) { this.executor = executor; } - public CompletableFuture enqueue(HttpChannelQueueCommand cmd) { + public CompletableFuture enqueue(HttpChannelQueueCommand cmd) { this.enqueue(cmd, this.executor); return cmd; } @Override - protected void prepare(HttpChannelQueueCommand item) { + protected void prepare(HttpChannelQueueCommand item) { item.run(); } @Override - protected void flush(HttpChannelQueueCommand item) { + protected void flush(HttpChannelQueueCommand item) { item.run(); item.getHttpChannel().flush(); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Request.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Request.java index 841f5ce280ed..d4cfd670e50f 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Request.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Request.java @@ -20,22 +20,19 @@ import org.apache.dubbo.remoting.http12.HttpInputMessage; import org.apache.dubbo.remoting.http12.RequestMetadata; -import java.io.IOException; -import java.io.InputStream; - -public final class DefaultHttp1Request implements Http1Request { +public final class DefaultHttp1Request implements Http1Request { private final RequestMetadata httpMetadata; - private final HttpInputMessage httpInputMessage; + private final HttpInputMessage httpInputMessage; - public DefaultHttp1Request(RequestMetadata httpMetadata, HttpInputMessage httpInputMessage) { + public DefaultHttp1Request(RequestMetadata httpMetadata, HttpInputMessage httpInputMessage) { this.httpMetadata = httpMetadata; this.httpInputMessage = httpInputMessage; } @Override - public InputStream getBody() { + public T getBody() { return httpInputMessage.getBody(); } @@ -55,7 +52,7 @@ public String path() { } @Override - public void close() throws IOException { + public void close() throws Exception { httpInputMessage.close(); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Response.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Response.java index 99a6993df4bb..7280b6912804 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Response.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Response.java @@ -20,22 +20,19 @@ import org.apache.dubbo.remoting.http12.HttpInputMessage; import org.apache.dubbo.remoting.http12.HttpMetadata; -import java.io.IOException; -import java.io.InputStream; - -public final class DefaultHttp1Response implements HttpMetadata, HttpInputMessage { +public final class DefaultHttp1Response implements HttpMetadata, HttpInputMessage { private final HttpMetadata httpMetadata; - private final HttpInputMessage httpInputMessage; + private final HttpInputMessage httpInputMessage; - public DefaultHttp1Response(HttpMetadata httpMetadata, HttpInputMessage httpInputMessage) { + public DefaultHttp1Response(HttpMetadata httpMetadata, HttpInputMessage httpInputMessage) { this.httpMetadata = httpMetadata; this.httpInputMessage = httpInputMessage; } @Override - public InputStream getBody() { + public T getBody() { return httpInputMessage.getBody(); } @@ -45,7 +42,7 @@ public HttpHeaders headers() { } @Override - public void close() throws IOException { + public void close() throws Exception { httpInputMessage.close(); } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1InputMessage.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1InputMessage.java index fdff9013b71a..5d0eced1448c 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1InputMessage.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1InputMessage.java @@ -18,18 +18,16 @@ import org.apache.dubbo.remoting.http12.HttpInputMessage; -import java.io.InputStream; +public final class Http1InputMessage implements HttpInputMessage { -public final class Http1InputMessage implements HttpInputMessage { + private final T body; - private final InputStream body; - - public Http1InputMessage(InputStream body) { + public Http1InputMessage(T body) { this.body = body; } @Override - public InputStream getBody() { + public T getBody() { return body; } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1OutputMessage.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1OutputMessage.java index e32574344939..e9e8c0960bcc 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1OutputMessage.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1OutputMessage.java @@ -18,29 +18,32 @@ import org.apache.dubbo.remoting.http12.HttpOutputMessage; -import java.io.IOException; -import java.io.OutputStream; - +import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufOutputStream; -public final class Http1OutputMessage implements HttpOutputMessage { +public final class Http1OutputMessage implements HttpOutputMessage { - private final OutputStream outputStream; + private final T body; - public Http1OutputMessage(OutputStream outputStream) { - this.outputStream = outputStream; + public Http1OutputMessage(T body) { + this.body = body; } @Override - public OutputStream getBody() { - return outputStream; + public T getBody() { + return body; } @Override - public void close() throws IOException { - if (outputStream instanceof ByteBufOutputStream) { - ((ByteBufOutputStream) outputStream).buffer().release(); + public void close() throws Exception { + if (body instanceof AutoCloseable) { + ((AutoCloseable) body).close(); + } + if (body instanceof ByteBufOutputStream) { + ((ByteBufOutputStream) body).buffer().release(); + } + if (body instanceof ByteBuf) { + ((ByteBuf) body).release(); } - outputStream.close(); } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1Request.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1Request.java index afe5ebf08289..3d1b818b51e9 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1Request.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1Request.java @@ -19,4 +19,4 @@ import org.apache.dubbo.remoting.http12.HttpInputMessage; import org.apache.dubbo.remoting.http12.RequestMetadata; -public interface Http1Request extends RequestMetadata, HttpInputMessage {} +public interface Http1Request extends RequestMetadata, HttpInputMessage {} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListener.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListener.java index 62b0d396a177..46e73ec0b42f 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListener.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListener.java @@ -20,4 +20,5 @@ import org.apache.dubbo.remoting.http12.HttpTransportListener; import org.apache.dubbo.remoting.http12.RequestMetadata; -public interface Http1ServerTransportListener extends HttpTransportListener {} +public interface Http1ServerTransportListener + extends HttpTransportListener, INPUT, OUTPUT> {} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListenerFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListenerFactory.java index 595ed1d475f9..3301a459541f 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListenerFactory.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListenerFactory.java @@ -20,10 +20,15 @@ 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.MessageTypeToken; import org.apache.dubbo.rpc.model.FrameworkModel; @SPI(scope = ExtensionScope.FRAMEWORK) public interface Http1ServerTransportListenerFactory { - Http1ServerTransportListener newInstance(HttpChannel httpChannel, URL url, FrameworkModel frameworkModel); + Http1ServerTransportListener newInstance( + HttpChannel httpChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/CancelableTransportListener.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/CancelableTransportListener.java index 71290b46e4d2..aae5512f7cbc 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/CancelableTransportListener.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/CancelableTransportListener.java @@ -20,8 +20,9 @@ import org.apache.dubbo.remoting.http12.HttpMetadata; import org.apache.dubbo.remoting.http12.HttpTransportListener; -public interface CancelableTransportListener
- extends HttpTransportListener { +public interface CancelableTransportListener< + HEADER extends HttpMetadata, MESSAGE extends HttpInputMessage, INPUT, OUTPUT> + extends HttpTransportListener { void cancelByRemote(long errorCode); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/H2StreamChannel.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/H2StreamChannel.java index 005043dcf3d4..5ad5bd62ca21 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/H2StreamChannel.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/H2StreamChannel.java @@ -20,14 +20,14 @@ import java.util.concurrent.CompletableFuture; -public interface H2StreamChannel extends HttpChannel { +public interface H2StreamChannel extends HttpChannel { CompletableFuture writeResetFrame(long errorCode); @Override - default Http2OutputMessage newOutputMessage() { + default Http2OutputMessage newOutputMessage() { return this.newOutputMessage(false); } - Http2OutputMessage newOutputMessage(boolean endStream); + Http2OutputMessage newOutputMessage(boolean endStream); } 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 e3c489ed5e3d..b419c112c582 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 @@ -22,15 +22,15 @@ import java.net.SocketAddress; import java.util.concurrent.CompletableFuture; -public class Http2ChannelDelegate implements H2StreamChannel { +public class Http2ChannelDelegate implements H2StreamChannel { - private final H2StreamChannel h2StreamChannel; + private final H2StreamChannel h2StreamChannel; - public Http2ChannelDelegate(H2StreamChannel h2StreamChannel) { + public Http2ChannelDelegate(H2StreamChannel h2StreamChannel) { this.h2StreamChannel = h2StreamChannel; } - public H2StreamChannel getH2StreamChannel() { + public H2StreamChannel getH2StreamChannel() { return h2StreamChannel; } @@ -40,7 +40,7 @@ public CompletableFuture writeHeader(HttpMetadata httpMetadata) { } @Override - public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { return h2StreamChannel.writeMessage(httpOutputMessage); } @@ -65,7 +65,7 @@ public CompletableFuture writeResetFrame(long errorCode) { } @Override - public Http2OutputMessage newOutputMessage(boolean endStream) { + public Http2OutputMessage newOutputMessage(boolean endStream) { return h2StreamChannel.newOutputMessage(endStream); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessage.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessage.java index 81ab23e321bd..bd32f3f9058d 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessage.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessage.java @@ -18,4 +18,4 @@ import org.apache.dubbo.remoting.http12.HttpInputMessage; -public interface Http2InputMessage extends HttpInputMessage, Http2StreamFrame {} +public interface Http2InputMessage extends HttpInputMessage, Http2StreamFrame {} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessageFrame.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessageFrame.java index 769f0dca360b..efaee4dc7baf 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessageFrame.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessageFrame.java @@ -18,28 +18,26 @@ import org.apache.dubbo.common.utils.ClassUtils; -import java.io.InputStream; - -public final class Http2InputMessageFrame implements Http2InputMessage { +public final class Http2InputMessageFrame implements Http2InputMessage { private final long streamId; - private final InputStream body; + private final T body; private final boolean endStream; - public Http2InputMessageFrame(InputStream body, boolean endStream) { + public Http2InputMessageFrame(T body, boolean endStream) { this(-1L, body, endStream); } - public Http2InputMessageFrame(long streamId, InputStream body, boolean endStream) { + public Http2InputMessageFrame(long streamId, T body, boolean endStream) { this.streamId = streamId; this.body = body; this.endStream = endStream; } @Override - public InputStream getBody() { + public T getBody() { return body; } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessage.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessage.java index ca2a07c8b9c7..df8e18f80cac 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessage.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessage.java @@ -18,7 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpOutputMessage; -public interface Http2OutputMessage extends HttpOutputMessage, Http2StreamFrame { +public interface Http2OutputMessage extends HttpOutputMessage, Http2StreamFrame { @Override default String name() { diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessageFrame.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessageFrame.java index 6a005893fc3c..99178fcd0aa7 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessageFrame.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessageFrame.java @@ -16,33 +16,36 @@ */ package org.apache.dubbo.remoting.http12.h2; -import java.io.IOException; -import java.io.OutputStream; - +import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufOutputStream; -public final class Http2OutputMessageFrame implements Http2OutputMessage { +public final class Http2OutputMessageFrame implements Http2OutputMessage { - private final OutputStream body; + private final T body; private final boolean endStream; - public Http2OutputMessageFrame(OutputStream body, boolean endStream) { + public Http2OutputMessageFrame(T body, boolean endStream) { this.body = body; this.endStream = endStream; } @Override - public OutputStream getBody() { + public T getBody() { return body; } @Override - public void close() throws IOException { + public void close() throws Exception { + if (body instanceof AutoCloseable) { + ((AutoCloseable) body).close(); + } if (body instanceof ByteBufOutputStream) { ((ByteBufOutputStream) body).buffer().release(); } - body.close(); + if (body instanceof ByteBuf) { + ((ByteBuf) body).release(); + } } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ServerTransportListenerFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ServerTransportListenerFactory.java index 3c955bac9df7..368279346d3a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ServerTransportListenerFactory.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ServerTransportListenerFactory.java @@ -19,12 +19,17 @@ 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.MessageTypeToken; import org.apache.dubbo.rpc.model.FrameworkModel; @SPI(scope = ExtensionScope.FRAMEWORK) public interface Http2ServerTransportListenerFactory { - Http2TransportListener newInstance(H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel); + Http2TransportListener newInstance( + H2StreamChannel streamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken); boolean supportContentType(String contentType); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2TransportListener.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2TransportListener.java index 2c4de2450493..f58d75a4dd81 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2TransportListener.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2TransportListener.java @@ -16,7 +16,8 @@ */ package org.apache.dubbo.remoting.http12.h2; -public interface Http2TransportListener extends CancelableTransportListener { +public interface Http2TransportListener + extends CancelableTransportListener, INPUT, OUTPUT> { void close(); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/command/Http2WriteQueueChannel.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/command/Http2WriteQueueChannel.java index ee2225599c20..5cb875d5778a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/command/Http2WriteQueueChannel.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/command/Http2WriteQueueChannel.java @@ -26,32 +26,32 @@ import java.util.concurrent.CompletableFuture; -public class Http2WriteQueueChannel extends Http2ChannelDelegate { +public class Http2WriteQueueChannel extends Http2ChannelDelegate { - private final HttpWriteQueue httpWriteQueue; + private final HttpWriteQueue httpWriteQueue; - public Http2WriteQueueChannel(H2StreamChannel h2StreamChannel, HttpWriteQueue httpWriteQueue) { + public Http2WriteQueueChannel(H2StreamChannel h2StreamChannel, HttpWriteQueue httpWriteQueue) { super(h2StreamChannel); this.httpWriteQueue = httpWriteQueue; } @Override public CompletableFuture writeHeader(HttpMetadata httpMetadata) { - HeaderQueueCommand cmd = new HeaderQueueCommand(httpMetadata); + HeaderQueueCommand cmd = new HeaderQueueCommand<>(httpMetadata); cmd.setHttpChannel(this::getH2StreamChannel); return httpWriteQueue.enqueue(cmd); } @Override - public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { - DataQueueCommand cmd = new DataQueueCommand(httpOutputMessage); + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + DataQueueCommand cmd = new DataQueueCommand<>(httpOutputMessage); cmd.setHttpChannel(this::getH2StreamChannel); return httpWriteQueue.enqueue(cmd); } @Override public CompletableFuture writeResetFrame(long errorCode) { - ResetQueueCommand cmd = new ResetQueueCommand(errorCode); + ResetQueueCommand cmd = new ResetQueueCommand<>(errorCode); cmd.setHttpChannel(this::getH2StreamChannel); return this.httpWriteQueue.enqueue(cmd); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/command/ResetQueueCommand.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/command/ResetQueueCommand.java index 79908ccc3f11..3305f983e1ac 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/command/ResetQueueCommand.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/command/ResetQueueCommand.java @@ -19,7 +19,7 @@ import org.apache.dubbo.remoting.http12.command.HttpChannelQueueCommand; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; -public class ResetQueueCommand extends HttpChannelQueueCommand { +public class ResetQueueCommand extends HttpChannelQueueCommand { private final long errorCode; @@ -29,7 +29,7 @@ public ResetQueueCommand(long errorCode) { @Override public void run() { - ((H2StreamChannel) getHttpChannel()).writeResetFrame(errorCode).whenComplete((unused, throwable) -> { + ((H2StreamChannel) getHttpChannel()).writeResetFrame(errorCode).whenComplete((unused, throwable) -> { if (throwable != null) { completeExceptionally(throwable); } else { diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/AbstractLengthFieldStreamingDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/AbstractLengthFieldStreamingDecoder.java new file mode 100644 index 000000000000..cc49aa0b7038 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/AbstractLengthFieldStreamingDecoder.java @@ -0,0 +1,125 @@ +/* + * 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.exception.DecodeException; + +public abstract class AbstractLengthFieldStreamingDecoder implements StreamingDecoder { + + private long pendingDeliveries; + private boolean inDelivery = false; + private boolean closing; + private boolean closed; + protected DecodeState state = DecodeState.HEADER; + protected final A accumulate; + protected FragmentListener listener; + protected final int lengthFieldOffset; + protected final int lengthFieldLength; + protected final int fixedHeaderLength; + protected int requiredLength; + + protected AbstractLengthFieldStreamingDecoder(A accumulate, int lengthFieldOffset, int lengthFieldLength) { + this.accumulate = accumulate; + this.lengthFieldOffset = lengthFieldOffset; + this.lengthFieldLength = lengthFieldLength; + this.requiredLength = lengthFieldOffset + lengthFieldLength; + this.fixedHeaderLength = requiredLength; + } + + @Override + public final void decode(T input) throws DecodeException { + if (closing || closed) { + return; + } + addInputToAccumulate(input); + deliver(); + } + + @Override + public final void request(int numMessages) { + pendingDeliveries += numMessages; + deliver(); + } + + @Override + public final void close() { + closing = true; + deliver(); + } + + @Override + public final void onStreamClosed() { + if (closed) { + return; + } + closed = true; + releaseAccumulate(); + } + + @Override + public final void setFragmentListener(FragmentListener listener) { + this.listener = listener; + } + + private void deliver() { + if (inDelivery || closed) { + return; + } + inDelivery = true; + try { + while (pendingDeliveries > 0 && hasEnoughBytes()) { + switch (state) { + case HEADER: + processHeader(); + break; + case PAYLOAD: + processBody(); + pendingDeliveries--; + break; + default: + throw new AssertionError("Invalid state: " + state); + } + } + if (closing && !closed) { + closed = true; + releaseAccumulate(); + listener.onClose(); + } + } catch (Exception e) { + throw new DecodeException(e); + } finally { + inDelivery = false; + } + } + + protected abstract void addInputToAccumulate(T input); + + protected abstract void releaseAccumulate(); + + protected abstract boolean hasEnoughBytes(); + + protected abstract void processHeader() throws Exception; + + protected abstract void processBody() throws Exception; + + public abstract void invokeListener(T rawMessage); + + protected enum DecodeState { + HEADER, + PAYLOAD + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufLengthFieldDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufLengthFieldDecoder.java new file mode 100644 index 000000000000..89a5903f90be --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufLengthFieldDecoder.java @@ -0,0 +1,77 @@ +/* + * 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 io.netty.buffer.ByteBuf; +import io.netty.buffer.CompositeByteBuf; +import io.netty.buffer.Unpooled; + +public class ByteBufLengthFieldDecoder extends AbstractLengthFieldStreamingDecoder { + + public ByteBufLengthFieldDecoder() { + this(0, 4); + } + + public ByteBufLengthFieldDecoder(int lengthFieldOffset, int lengthFieldLength) { + super(Unpooled.compositeBuffer(), lengthFieldOffset, lengthFieldLength); + } + + @Override + protected void addInputToAccumulate(ByteBuf input) { + accumulate.addComponent(true, input); + } + + @Override + protected void releaseAccumulate() { + accumulate.clear(); + accumulate.release(); + } + + @Override + protected boolean hasEnoughBytes() { + return requiredLength <= accumulate.readableBytes(); + } + + @Override + protected void processHeader() { + accumulate.skipBytes(lengthFieldOffset); + requiredLength = readLengthField(accumulate, lengthFieldLength); + state = DecodeState.PAYLOAD; + } + + @Override + protected void processBody() { + ByteBuf rawMessage = accumulate.readSlice(requiredLength); + invokeListener(rawMessage); + state = DecodeState.HEADER; + requiredLength = fixedHeaderLength; + accumulate.discardReadComponents(); + } + + @Override + public void invokeListener(ByteBuf rawMessage) { + listener.onFragmentMessage(rawMessage); + } + + protected int readLengthField(ByteBuf buffer, int length) { + int result = 0; + for (int i = 0; i < length; i++) { + result = (result << 8) | (buffer.readByte() & 0xFF); + } + return result; + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufMessageCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufMessageCodec.java new file mode 100644 index 000000000000..2bc3f6112f90 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufMessageCodec.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.remoting.http12.message; + +public interface ByteBufMessageCodec extends ByteBufMessageEncoder, ByteBufMessageDecoder {} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufMessageDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufMessageDecoder.java new file mode 100644 index 000000000000..c427d8c0ab4b --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufMessageDecoder.java @@ -0,0 +1,59 @@ +/* + * 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.ArrayUtils; +import org.apache.dubbo.remoting.http12.exception.DecodeException; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.nio.charset.Charset; + +import io.netty.buffer.ByteBuf; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public interface ByteBufMessageDecoder extends CodecMediaType { + + Object decode(ByteBuf buffer, Class targetType, Charset charset) throws DecodeException; + + default Object decode(ByteBuf buffer, Type targetType, Charset charset) throws DecodeException { + if (targetType instanceof Class) { + return decode(buffer, (Class) targetType, charset); + } + if (targetType instanceof ParameterizedType) { + return decode(buffer, (Class) ((ParameterizedType) targetType).getRawType(), charset); + } + throw new DecodeException("targetType " + targetType + " is not a class"); + } + + default Object[] decode(ByteBuf buffer, Class[] targetTypes, Charset charset) throws DecodeException { + return new Object[] {decode(buffer, ArrayUtils.isEmpty(targetTypes) ? null : targetTypes[0], charset)}; + } + + default Object decode(ByteBuf buffer, Class targetType) throws DecodeException { + return decode(buffer, targetType, UTF_8); + } + + default Object decode(ByteBuf buffer, Type targetType) throws DecodeException { + return decode(buffer, targetType, UTF_8); + } + + default Object[] decode(ByteBuf buffer, Class[] targetTypes) throws DecodeException { + return decode(buffer, targetTypes, UTF_8); + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufMessageEncoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufMessageEncoder.java new file mode 100644 index 000000000000..b50022bb2694 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufMessageEncoder.java @@ -0,0 +1,47 @@ +/* + * 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.ArrayUtils; +import org.apache.dubbo.remoting.http12.exception.EncodeException; + +import java.nio.charset.Charset; + +import io.netty.buffer.ByteBuf; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public interface ByteBufMessageEncoder extends CodecMediaType { + + void encode(ByteBuf buffer, Object data, Charset charset) throws EncodeException; + + default void encode(ByteBuf buffer, Object[] data, Charset charset) throws EncodeException { + encode(buffer, ArrayUtils.first(data), charset); + } + + default void encode(ByteBuf buffer, Object data) throws EncodeException { + encode(buffer, data, UTF_8); + } + + default void encode(ByteBuf buffer, Object[] data) throws EncodeException { + encode(buffer, ArrayUtils.first(data), UTF_8); + } + + default String contentType() { + return mediaType().getName(); + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufResponseEncoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufResponseEncoder.java new file mode 100644 index 000000000000..30c84746f2f3 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ByteBufResponseEncoder.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.remoting.http12.message; + +import io.netty.buffer.ByteBuf; + +public class ByteBufResponseEncoder implements ResponseEncoder { + + private final HttpMessageEncoder httpMessageEncoder; + + public ByteBufResponseEncoder(HttpMessageEncoder httpMessageEncoder) { + this.httpMessageEncoder = httpMessageEncoder; + } + + @Override + public void encode(ByteBuf output, Object response) { + httpMessageEncoder.encode(output, response); + } + + @Override + public HttpMessageEncoder delegate() { + return httpMessageEncoder; + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultByteBufListeningDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultByteBufListeningDecoder.java new file mode 100644 index 000000000000..f71cccdad589 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultByteBufListeningDecoder.java @@ -0,0 +1,49 @@ +/* + * 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 io.netty.buffer.ByteBuf; + +public class DefaultByteBufListeningDecoder implements ListeningDecoder { + + private final HttpMessageDecoder httpMessageDecoder; + + private final Class[] targetTypes; + + private Listener listener; + + public DefaultByteBufListeningDecoder(HttpMessageDecoder httpMessageDecoder, Class[] targetTypes) { + this.httpMessageDecoder = httpMessageDecoder; + this.targetTypes = targetTypes; + } + + @Override + public void setListener(Listener listener) { + this.listener = listener; + } + + @Override + public void decode(ByteBuf buffer) { + Object[] decode = this.httpMessageDecoder.decode(buffer, targetTypes); + this.listener.onMessage(decode); + } + + @Override + public void close() { + this.listener.onClose(); + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java index dfb02c63de2a..58f74d01ae33 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java @@ -18,7 +18,7 @@ import java.io.InputStream; -public class DefaultListeningDecoder implements ListeningDecoder { +public class DefaultListeningDecoder implements ListeningDecoder { private final HttpMessageDecoder httpMessageDecoder; diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultStreamingDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultStreamingDecoder.java index 9fb1d43830e2..4ca81e70ca9b 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultStreamingDecoder.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultStreamingDecoder.java @@ -22,13 +22,13 @@ import java.io.IOException; import java.io.InputStream; -public class DefaultStreamingDecoder implements StreamingDecoder { +public class DefaultStreamingDecoder implements StreamingDecoder { private boolean closed; protected final CompositeInputStream accumulate = new CompositeInputStream(); - protected FragmentListener listener = NoopFragmentListener.NOOP; + protected FragmentListener listener = StreamingDecoder.noop(); @Override public void request(int numMessages) { @@ -73,7 +73,7 @@ public void onStreamClosed() { } @Override - public void setFragmentListener(FragmentListener listener) { + public void setFragmentListener(FragmentListener listener) { this.listener = listener; } } 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 53c4e8477995..3abc44576b83 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 @@ -24,6 +24,9 @@ import java.lang.reflect.Type; import java.nio.charset.Charset; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; + import static java.nio.charset.StandardCharsets.UTF_8; public interface HttpMessageDecoder extends CodecMediaType { @@ -55,4 +58,20 @@ default Object decode(InputStream inputStream, Type targetType) throws DecodeExc default Object[] decode(InputStream inputStream, Class[] targetTypes) throws DecodeException { return decode(inputStream, targetTypes, UTF_8); } + + default Object decode(ByteBuf buffer, Class targetType, Charset charset) throws DecodeException { + return decode(new ByteBufInputStream(buffer), targetType, charset); + } + + default Object[] decode(ByteBuf buffer, Class[] targetTypes, Charset charset) throws DecodeException { + return new Object[] {decode(buffer, ArrayUtils.isEmpty(targetTypes) ? null : targetTypes[0], charset)}; + } + + default Object decode(ByteBuf buffer, Class targetType) throws DecodeException { + return decode(buffer, targetType, UTF_8); + } + + default Object[] decode(ByteBuf buffer, Class[] targetTypes) throws DecodeException { + return decode(buffer, targetTypes, UTF_8); + } } 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 f4890bcb3b92..4595a0103698 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 @@ -22,6 +22,9 @@ import java.io.OutputStream; import java.nio.charset.Charset; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufOutputStream; + import static java.nio.charset.StandardCharsets.UTF_8; public interface HttpMessageEncoder extends CodecMediaType { @@ -40,6 +43,22 @@ default void encode(OutputStream outputStream, Object[] data) throws EncodeExcep encode(outputStream, ArrayUtils.first(data), UTF_8); } + default void encode(ByteBuf buffer, Object data, Charset charset) throws EncodeException { + encode(new ByteBufOutputStream(buffer), data, charset); + } + + default void encode(ByteBuf buffer, Object[] data, Charset charset) throws EncodeException { + encode(buffer, ArrayUtils.first(data), charset); + } + + default void encode(ByteBuf buffer, Object data) throws EncodeException { + encode(buffer, data, UTF_8); + } + + default void encode(ByteBuf buffer, Object[] data) throws EncodeException { + encode(buffer, ArrayUtils.first(data), UTF_8); + } + default String contentType() { return mediaType().getName(); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/InputStreamLengthFieldDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/InputStreamLengthFieldDecoder.java new file mode 100644 index 000000000000..e79b57d6d44f --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/InputStreamLengthFieldDecoder.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.message; + +import org.apache.dubbo.remoting.http12.CompositeInputStream; +import org.apache.dubbo.remoting.http12.exception.DecodeException; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class InputStreamLengthFieldDecoder + extends AbstractLengthFieldStreamingDecoder { + + public InputStreamLengthFieldDecoder() { + this(0, 4); + } + + public InputStreamLengthFieldDecoder(int lengthFieldOffset, int lengthFieldLength) { + super(new CompositeInputStream(), lengthFieldOffset, lengthFieldLength); + } + + @Override + protected void addInputToAccumulate(InputStream input) { + accumulate.addInputStream(input); + } + + @Override + protected void releaseAccumulate() { + try { + accumulate.close(); + } catch (IOException e) { + throw new DecodeException(e); + } + } + + @Override + protected boolean hasEnoughBytes() { + return requiredLength <= accumulate.available(); + } + + @Override + protected void processHeader() throws IOException { + byte[] offsetData = new byte[lengthFieldOffset]; + accumulate.read(offsetData); + requiredLength = readLengthField(accumulate, lengthFieldLength); + state = DecodeState.PAYLOAD; + } + + @Override + protected void processBody() throws IOException { + byte[] rawMessage = new byte[requiredLength]; + accumulate.read(rawMessage); + invokeListener(new ByteArrayInputStream(rawMessage)); + state = DecodeState.HEADER; + requiredLength = fixedHeaderLength; + } + + @Override + public void invokeListener(InputStream rawMessage) { + listener.onFragmentMessage(rawMessage); + } + + protected int readLengthField(InputStream input, int length) throws IOException { + int result = 0; + for (int i = 0; i < length; i++) { + result = (result << 8) | (input.read() & 0xFF); + } + return result; + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/LengthFieldStreamingDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/LengthFieldStreamingDecoder.java deleted file mode 100644 index 77821ea431a4..000000000000 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/LengthFieldStreamingDecoder.java +++ /dev/null @@ -1,201 +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.remoting.http12.message; - -import org.apache.dubbo.remoting.http12.CompositeInputStream; -import org.apache.dubbo.remoting.http12.exception.DecodeException; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -public class LengthFieldStreamingDecoder implements StreamingDecoder { - - private long pendingDeliveries; - - private boolean inDelivery = false; - - private boolean closing; - - private boolean closed; - - private DecodeState state = DecodeState.HEADER; - - private final CompositeInputStream accumulate = new CompositeInputStream(); - - private FragmentListener listener; - - private final int lengthFieldOffset; - - private final int lengthFieldLength; - - private int requiredLength; - - public LengthFieldStreamingDecoder() { - this(4); - } - - public LengthFieldStreamingDecoder(int lengthFieldLength) { - this(0, lengthFieldLength); - } - - public LengthFieldStreamingDecoder(int lengthFieldOffset, int lengthFieldLength) { - this.lengthFieldOffset = lengthFieldOffset; - this.lengthFieldLength = lengthFieldLength; - this.requiredLength = lengthFieldOffset + lengthFieldLength; - } - - @Override - public final void decode(InputStream inputStream) throws DecodeException { - if (closing || closed) { - // ignored - return; - } - accumulate.addInputStream(inputStream); - deliver(); - } - - @Override - public final void request(int numMessages) { - pendingDeliveries += numMessages; - deliver(); - } - - @Override - public final void close() { - closing = true; - deliver(); - } - - @Override - public final void onStreamClosed() { - if (closed) { - return; - } - closed = true; - try { - accumulate.close(); - } catch (IOException e) { - throw new DecodeException(e); - } - } - - @Override - public final void setFragmentListener(FragmentListener listener) { - this.listener = listener; - } - - private void deliver() { - // We can have reentrancy here when using a direct executor, triggered by calls to - // request more messages. This is safe as we simply loop until pendingDelivers = 0 - if (inDelivery) { - return; - } - if (closed) { - return; - } - inDelivery = true; - try { - // Process the uncompressed bytes. - while (pendingDeliveries > 0 && hasEnoughBytes()) { - switch (state) { - case HEADER: - processHeader(); - break; - case PAYLOAD: - // Read the body and deliver the message. - processBody(); - - // Since we've delivered a message, decrement the number of pending - // deliveries remaining. - pendingDeliveries--; - break; - default: - throw new AssertionError("Invalid state: " + state); - } - } - if (closing) { - if (!closed) { - closed = true; - accumulate.close(); - listener.onClose(); - } - } - } catch (IOException e) { - throw new DecodeException(e); - } finally { - inDelivery = false; - } - } - - private void processHeader() throws IOException { - byte[] offsetData = new byte[lengthFieldOffset]; - int ignore = accumulate.read(offsetData); - processOffset(new ByteArrayInputStream(offsetData), lengthFieldOffset); - byte[] lengthBytes = new byte[lengthFieldLength]; - ignore = accumulate.read(lengthBytes); - requiredLength = bytesToInt(lengthBytes); - - // Continue reading the frame body. - state = DecodeState.PAYLOAD; - } - - protected void processOffset(InputStream inputStream, int lengthFieldOffset) throws IOException { - // default skip offset - skipOffset(inputStream, lengthFieldOffset); - } - - private void skipOffset(InputStream inputStream, int lengthFieldOffset) throws IOException { - if (lengthFieldOffset != 0) { - return; - } - int ignore = inputStream.read(new byte[lengthFieldOffset]); - } - - private void processBody() throws IOException { - byte[] rawMessage = readRawMessage(accumulate, requiredLength); - InputStream inputStream = new ByteArrayInputStream(rawMessage); - invokeListener(inputStream); - - // Done with this frame, begin processing the next header. - state = DecodeState.HEADER; - requiredLength = lengthFieldOffset + lengthFieldLength; - } - - public void invokeListener(InputStream inputStream) { - this.listener.onFragmentMessage(inputStream); - } - - protected byte[] readRawMessage(InputStream inputStream, int length) throws IOException { - byte[] data = new byte[length]; - inputStream.read(data, 0, length); - return data; - } - - private boolean hasEnoughBytes() { - return requiredLength - accumulate.available() <= 0; - } - - protected static int bytesToInt(byte[] bytes) { - return ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) | ((bytes[2] & 0xFF) << 8) | (bytes[3]) & 0xFF; - } - - private enum DecodeState { - HEADER, - PAYLOAD - } -} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ListeningDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ListeningDecoder.java index af29e6b750eb..e56d4e182f71 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ListeningDecoder.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ListeningDecoder.java @@ -18,11 +18,9 @@ import org.apache.dubbo.remoting.http12.exception.DecodeException; -import java.io.InputStream; +public interface ListeningDecoder { -public interface ListeningDecoder { - - void decode(InputStream inputStream) throws DecodeException; + void decode(T input) throws DecodeException; void close(); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/NettyStreamingDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/NettyStreamingDecoder.java new file mode 100644 index 000000000000..bde4e1a13009 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/NettyStreamingDecoder.java @@ -0,0 +1,81 @@ +/* + * 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.exception.DecodeException; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.CompositeByteBuf; +import io.netty.buffer.Unpooled; + +public class NettyStreamingDecoder implements StreamingDecoder { + + private boolean closed; + + protected final CompositeByteBuf accumulate = Unpooled.compositeBuffer(); + + protected FragmentListener listener = StreamingDecoder.noop(); + + @Override + public void request(int numMessages) { + // do nothing + } + + @Override + public void decode(ByteBuf buffer) throws DecodeException { + if (closed) { + // ignored + return; + } + accumulate.addComponent(buffer); + } + + @Override + public void close() { + try { + if (closed) { + return; + } + closed = true; + listener.onFragmentMessage(accumulate); + accumulate.clear(); + accumulate.release(); + listener.onClose(); + } catch (Exception e) { + throw new DecodeException(e); + } + } + + @Override + public void onStreamClosed() { + if (closed) { + return; + } + closed = true; + try { + accumulate.clear(); + accumulate.release(); + } catch (Exception e) { + throw new DecodeException(e); + } + } + + @Override + public void setFragmentListener(FragmentListener listener) { + this.listener = listener; + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/OutputStreamResponseEncoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/OutputStreamResponseEncoder.java new file mode 100644 index 000000000000..cb827d54e3a2 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/OutputStreamResponseEncoder.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.remoting.http12.message; + +import java.io.OutputStream; + +public class OutputStreamResponseEncoder implements ResponseEncoder { + + private final HttpMessageEncoder httpMessageEncoder; + + public OutputStreamResponseEncoder(HttpMessageEncoder httpMessageEncoder) { + this.httpMessageEncoder = httpMessageEncoder; + } + + @Override + public void encode(OutputStream output, Object response) { + httpMessageEncoder.encode(output, response); + } + + @Override + public HttpMessageEncoder delegate() { + return httpMessageEncoder; + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ResponseEncoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ResponseEncoder.java new file mode 100644 index 000000000000..d613dfcd14d6 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/ResponseEncoder.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.remoting.http12.message; + +public interface ResponseEncoder { + + void encode(OUTPUT output, Object response); + + HttpMessageEncoder delegate(); + + default String contentType() { + return delegate().contentType(); + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/StreamingDecoder.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/StreamingDecoder.java index b0471f090b3e..daec3e3d769d 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/StreamingDecoder.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/StreamingDecoder.java @@ -18,40 +18,38 @@ import org.apache.dubbo.remoting.http12.exception.DecodeException; -import java.io.InputStream; - -public interface StreamingDecoder { +public interface StreamingDecoder { void request(int numMessages); - void decode(InputStream inputStream) throws DecodeException; + void decode(T input) throws DecodeException; void close(); void onStreamClosed(); - void setFragmentListener(FragmentListener listener); + void setFragmentListener(FragmentListener listener); - interface FragmentListener { + interface FragmentListener { /** * @param rawMessage raw message */ - void onFragmentMessage(InputStream rawMessage); + void onFragmentMessage(T rawMessage); default void onClose() {} } - final class DefaultFragmentListener implements FragmentListener { + final class DefaultFragmentListener implements FragmentListener { - private final ListeningDecoder listeningDecoder; + private final ListeningDecoder listeningDecoder; - public DefaultFragmentListener(ListeningDecoder listeningDecoder) { + public DefaultFragmentListener(ListeningDecoder listeningDecoder) { this.listeningDecoder = listeningDecoder; } @Override - public void onFragmentMessage(InputStream rawMessage) { + public void onFragmentMessage(T rawMessage) { listeningDecoder.decode(rawMessage); } @@ -61,13 +59,20 @@ public void onClose() { } } - final class NoopFragmentListener implements FragmentListener { + @SuppressWarnings("unchecked") + static FragmentListener noop() { + return (FragmentListener) NoopFragmentListener.NOOP; + } + + final class NoopFragmentListener implements FragmentListener { - static final FragmentListener NOOP = new NoopFragmentListener(); + private static final NoopFragmentListener NOOP = new NoopFragmentListener<>(); private NoopFragmentListener() {} @Override - public void onFragmentMessage(InputStream rawMessage) {} + public void onFragmentMessage(T rawMessage) { + // no-op + } } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/ForyCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/ForyCodec.java new file mode 100644 index 000000000000..6b6e3749730b --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/ForyCodec.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.remoting.http12.message.codec; + +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.MediaType; + +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; + +import io.netty.buffer.ByteBuf; +import org.apache.fory.Fory; +import org.apache.fory.config.Language; +import org.apache.fory.io.ForyStreamReader; +import org.apache.fory.memory.MemoryBuffer; + +public class ForyCodec implements HttpMessageCodec { + + private static final Fory fory = Fory.builder() + .withLanguage(Language.JAVA) + .withRefTracking(true) + .requireClassRegistration(false) + .build(); + + @Override + public MediaType mediaType() { + return MediaType.APPLICATION_GRPC; + } + + @Override + public Object decode(InputStream inputStream, Class targetType, Charset charset) throws DecodeException { + return fory.deserialize(ForyStreamReader.of(inputStream)); + } + + @Override + public Object decode(ByteBuf buffer, Class targetType, Charset charset) throws DecodeException { + MemoryBuffer memoryBuffer = MemoryBuffer.fromByteBuffer(buffer.nioBuffer()); + return fory.deserialize(memoryBuffer); + } + + @Override + public void encode(OutputStream outputStream, Object data, Charset charset) throws EncodeException { + fory.serialize(outputStream, data); + } + + @Override + public void encode(ByteBuf buffer, Object data, Charset charset) throws EncodeException { + // MemoryBuffer memoryBuffer = MemoryBuffer.fromByteBuffer(buffer); + // fory.serialize(memoryBuffer, data); + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/EmptyByteBufMessage.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/EmptyByteBufMessage.java new file mode 100644 index 000000000000..bb5a79e1bce0 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/EmptyByteBufMessage.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.remoting.http12.netty4; + +import org.apache.dubbo.remoting.http12.HttpInputMessage; +import org.apache.dubbo.remoting.http12.HttpOutputMessage; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +public class EmptyByteBufMessage implements HttpInputMessage, HttpOutputMessage { + + public static final EmptyByteBufMessage INSTANCE = new EmptyByteBufMessage(); + + @Override + public ByteBuf getBody() { + return Unpooled.EMPTY_BUFFER; + } + + @Override + public void close() throws Exception { + // no op + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/HttpWriteQueueHandler.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/HttpWriteQueueHandler.java index a81a983af9e9..8660f3649ced 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/HttpWriteQueueHandler.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/HttpWriteQueueHandler.java @@ -18,18 +18,19 @@ import org.apache.dubbo.remoting.http12.command.HttpWriteQueue; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.EventLoop; public class HttpWriteQueueHandler extends ChannelInboundHandlerAdapter { - private HttpWriteQueue writeQueue; + private HttpWriteQueue writeQueue; @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { EventLoop eventLoop = ctx.channel().eventLoop(); - this.writeQueue = new HttpWriteQueue(eventLoop); + this.writeQueue = new HttpWriteQueue<>(eventLoop); } @Override @@ -37,7 +38,7 @@ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { this.writeQueue = null; } - public HttpWriteQueue getWriteQueue() { + public HttpWriteQueue getWriteQueue() { return writeQueue; } } 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 19d0c807d059..ce9aa301f8af 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 @@ -20,16 +20,16 @@ import org.apache.dubbo.remoting.http12.HttpChannel; import org.apache.dubbo.remoting.http12.HttpMetadata; import org.apache.dubbo.remoting.http12.HttpOutputMessage; -import org.apache.dubbo.remoting.http12.LimitedByteBufOutputStream; import org.apache.dubbo.remoting.http12.h1.Http1OutputMessage; import org.apache.dubbo.remoting.http12.netty4.NettyHttpChannelFutureListener; import java.net.SocketAddress; import java.util.concurrent.CompletableFuture; +import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; -public class NettyHttp1Channel implements HttpChannel { +public class NettyHttp1Channel implements HttpChannel { private final Channel channel; @@ -48,16 +48,15 @@ public CompletableFuture writeHeader(HttpMetadata httpMetadata) { } @Override - public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { NettyHttpChannelFutureListener nettyHttpChannelFutureListener = new NettyHttpChannelFutureListener(); this.channel.writeAndFlush(httpOutputMessage).addListener(nettyHttpChannelFutureListener); return nettyHttpChannelFutureListener; } @Override - public HttpOutputMessage newOutputMessage() { - return new Http1OutputMessage(new LimitedByteBufOutputStream( - channel.alloc().buffer(), tripleConfig.getMaxResponseBodySizeOrDefault())); + public HttpOutputMessage newOutputMessage() { + return new Http1OutputMessage<>(channel.alloc().buffer()); } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1Codec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1Codec.java index 594b77e63a34..cef37bbb66eb 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1Codec.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1Codec.java @@ -23,13 +23,11 @@ import org.apache.dubbo.remoting.http12.h1.DefaultHttp1Request; import org.apache.dubbo.remoting.http12.h1.Http1InputMessage; import org.apache.dubbo.remoting.http12.h1.Http1RequestMetadata; +import org.apache.dubbo.remoting.http12.netty4.EmptyByteBufMessage; -import java.io.OutputStream; import java.util.List; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufInputStream; -import io.netty.buffer.ByteBufOutputStream; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; @@ -54,17 +52,18 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception keepAlive = HttpUtil.isKeepAlive(request); super.channelRead( ctx, - new DefaultHttp1Request( + new DefaultHttp1Request<>( new Http1RequestMetadata( new NettyHttp1HttpHeaders(request.headers()), request.method().name(), request.uri()), - new Http1InputMessage(new ByteBufInputStream(request.content(), true)))); + new Http1InputMessage<>(request.content()))); return; } super.channelRead(ctx, msg); } + @SuppressWarnings("unchecked") @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { if (msg instanceof HttpMetadata) { @@ -72,7 +71,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) return; } if (msg instanceof HttpOutputMessage) { - doWriteMessage(ctx, ((HttpOutputMessage) msg), promise); + doWriteMessage(ctx, ((HttpOutputMessage) msg), promise); return; } super.write(ctx, msg, promise); @@ -95,8 +94,8 @@ private void doWriteHeader(ChannelHandlerContext ctx, HttpMetadata msg, ChannelP ctx.writeAndFlush(new DefaultHttpResponse(HttpVersion.HTTP_1_1, status, headers.getHeaders()), promise); } - private void doWriteMessage(ChannelHandlerContext ctx, HttpOutputMessage msg, ChannelPromise promise) { - if (HttpOutputMessage.EMPTY_MESSAGE == msg) { + private void doWriteMessage(ChannelHandlerContext ctx, HttpOutputMessage msg, ChannelPromise promise) { + if (EmptyByteBufMessage.INSTANCE == msg) { if (keepAlive) { ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT, promise); } else { @@ -104,12 +103,7 @@ private void doWriteMessage(ChannelHandlerContext ctx, HttpOutputMessage msg, Ch } return; } - OutputStream body = msg.getBody(); - if (body instanceof ByteBufOutputStream) { - ByteBuf buffer = ((ByteBufOutputStream) body).buffer(); - ctx.writeAndFlush(buffer, promise); - return; - } - throw new IllegalArgumentException("HttpOutputMessage body must be 'io.netty.buffer.ByteBufOutputStream'"); + ByteBuf body = msg.getBody(); + ctx.writeAndFlush(body, promise); } } 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 72649fce24e4..154baa4b3571 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,15 +18,17 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.config.nested.TripleConfig; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h1.Http1Request; import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener; import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListenerFactory; import org.apache.dubbo.rpc.model.FrameworkModel; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; -public class NettyHttp1ConnectionHandler extends SimpleChannelInboundHandler { +public class NettyHttp1ConnectionHandler extends SimpleChannelInboundHandler> { private final URL url; @@ -50,9 +52,13 @@ public NettyHttp1ConnectionHandler( /** * process h1 request */ - protected void channelRead0(ChannelHandlerContext ctx, Http1Request http1Request) { - Http1ServerTransportListener http1TransportListener = http1ServerTransportListenerFactory.newInstance( - new NettyHttp1Channel(ctx.channel(), tripleConfig), url, frameworkModel); + protected void channelRead0(ChannelHandlerContext ctx, Http1Request http1Request) { + Http1ServerTransportListener http1TransportListener = + http1ServerTransportListenerFactory.newInstance( + new NettyHttp1Channel(ctx.channel(), tripleConfig), + url, + frameworkModel, + new MessageTypeToken() {}); 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 c28449d28bbc..7688851a5481 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 @@ -19,7 +19,6 @@ import org.apache.dubbo.config.nested.TripleConfig; import org.apache.dubbo.remoting.http12.HttpMetadata; import org.apache.dubbo.remoting.http12.HttpOutputMessage; -import org.apache.dubbo.remoting.http12.LimitedByteBufOutputStream; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2OutputMessage; import org.apache.dubbo.remoting.http12.h2.Http2OutputMessageFrame; @@ -29,11 +28,10 @@ import java.util.concurrent.CompletableFuture; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufOutputStream; import io.netty.handler.codec.http2.DefaultHttp2ResetFrame; import io.netty.handler.codec.http2.Http2StreamChannel; -public class NettyH2StreamChannel implements H2StreamChannel { +public class NettyH2StreamChannel implements H2StreamChannel { private final Http2StreamChannel http2StreamChannel; @@ -53,18 +51,15 @@ public CompletableFuture writeHeader(HttpMetadata httpMetadata) { } @Override - public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { NettyHttpChannelFutureListener nettyHttpChannelFutureListener = new NettyHttpChannelFutureListener(); http2StreamChannel.write(httpOutputMessage).addListener(nettyHttpChannelFutureListener); return nettyHttpChannelFutureListener; } @Override - public Http2OutputMessage newOutputMessage(boolean endStream) { - ByteBuf buffer = http2StreamChannel.alloc().buffer(); - ByteBufOutputStream outputStream = - new LimitedByteBufOutputStream(buffer, tripleConfig.getMaxResponseBodySizeOrDefault()); - return new Http2OutputMessageFrame(outputStream, endStream); + public Http2OutputMessage newOutputMessage(boolean endStream) { + return new Http2OutputMessageFrame<>(http2StreamChannel.alloc().buffer(), endStream); } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2FrameCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2FrameCodec.java index 2a8ad9a08748..a108293a8294 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2FrameCodec.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2FrameCodec.java @@ -26,14 +26,11 @@ import org.apache.dubbo.remoting.http12.message.DefaultHttpHeaders; import org.apache.dubbo.remoting.http12.netty4.NettyHttpHeaders; -import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufInputStream; -import io.netty.buffer.ByteBufOutputStream; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; @@ -156,9 +153,8 @@ private Http2Header onHttp2HeadersFrame(Http2HeadersFrame headersFrame) { headersFrame.stream().id(), new DefaultHttpHeaders(headersFrame.headers()), headersFrame.isEndStream()); } - private Http2InputMessage onHttp2DataFrame(Http2DataFrame dataFrame) { - return new Http2InputMessageFrame( - dataFrame.stream().id(), new ByteBufInputStream(dataFrame.content(), true), dataFrame.isEndStream()); + private Http2InputMessage onHttp2DataFrame(Http2DataFrame dataFrame) { + return new Http2InputMessageFrame<>(dataFrame.stream().id(), dataFrame.content(), dataFrame.isEndStream()); } @SuppressWarnings("unchecked") @@ -167,16 +163,12 @@ private Http2HeadersFrame encodeHttp2HeadersFrame(Http2Header http2Header) { ((NettyHttpHeaders) http2Header.headers()).getHeaders(), http2Header.isEndStream()); } - private Http2DataFrame encodeHttp2DataFrame(Http2OutputMessage outputMessage) { - OutputStream body = outputMessage.getBody(); + private Http2DataFrame encodeHttp2DataFrame(Http2OutputMessage outputMessage) { + ByteBuf body = outputMessage.getBody(); if (body == null) { return new DefaultHttp2DataFrame(outputMessage.isEndStream()); } - if (body instanceof ByteBufOutputStream) { - ByteBuf buffer = ((ByteBufOutputStream) body).buffer(); - return new DefaultHttp2DataFrame(buffer, outputMessage.isEndStream()); - } - throw new IllegalArgumentException("Http2OutputMessage body must be ByteBufOutputStream"); + return new DefaultHttp2DataFrame(body, outputMessage.isEndStream()); } private static class CachedMsg { 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 c23e176531e1..0ae09198a8e6 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 @@ -22,6 +22,7 @@ import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.config.nested.TripleConfig; import org.apache.dubbo.remoting.http12.HttpMetadata; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.command.HttpWriteQueue; import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; @@ -33,6 +34,7 @@ import java.util.Set; +import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; @@ -74,13 +76,14 @@ protected void channelRead0(ChannelHandlerContext ctx, HttpMetadata metadata) { throw new UnsupportedMediaTypeException(contentType); } Channel channel = ctx.channel(); - H2StreamChannel h2StreamChannel = new NettyH2StreamChannel((Http2StreamChannel) channel, tripleConfig); + H2StreamChannel h2StreamChannel = new NettyH2StreamChannel((Http2StreamChannel) channel, tripleConfig); HttpWriteQueueHandler writeQueueHandler = channel.parent().pipeline().get(HttpWriteQueueHandler.class); if (writeQueueHandler != null) { - HttpWriteQueue writeQueue = writeQueueHandler.getWriteQueue(); - h2StreamChannel = new Http2WriteQueueChannel(h2StreamChannel, writeQueue); + HttpWriteQueue writeQueue = writeQueueHandler.getWriteQueue(); + h2StreamChannel = new Http2WriteQueueChannel<>(h2StreamChannel, writeQueue); } - Http2TransportListener http2TransportListener = factory.newInstance(h2StreamChannel, url, frameworkModel); + Http2TransportListener http2TransportListener = + factory.newInstance(h2StreamChannel, url, frameworkModel, new MessageTypeToken() {}); channel.closeFuture().addListener(future -> http2TransportListener.close()); ctx.pipeline() .addLast(new NettyHttp2FrameHandler(h2StreamChannel, http2TransportListener)) diff --git a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/Http3ServerTransportListenerFactory.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/Http3ServerTransportListenerFactory.java index 1cd6d1738117..0513789e828a 100644 --- a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/Http3ServerTransportListenerFactory.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/Http3ServerTransportListenerFactory.java @@ -19,13 +19,18 @@ 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.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.rpc.model.FrameworkModel; @SPI(scope = ExtensionScope.FRAMEWORK) public interface Http3ServerTransportListenerFactory { - Http3TransportListener newInstance(H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel); + Http3TransportListener newInstance( + H2StreamChannel streamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken); boolean supportContentType(String contentType); } diff --git a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/Http3TransportListener.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/Http3TransportListener.java index 87eb7ad9838d..02b12c87a317 100644 --- a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/Http3TransportListener.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/Http3TransportListener.java @@ -18,4 +18,4 @@ import org.apache.dubbo.remoting.http12.h2.Http2TransportListener; -public interface Http3TransportListener extends Http2TransportListener {} +public interface Http3TransportListener extends Http2TransportListener {} diff --git a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3FrameCodec.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3FrameCodec.java index f49a4fa8f453..709f598989fd 100644 --- a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3FrameCodec.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3FrameCodec.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.remoting.http3.netty4; -import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.remoting.http12.HttpStatus; import org.apache.dubbo.remoting.http12.h2.Http2Header; import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame; @@ -25,11 +24,10 @@ import org.apache.dubbo.remoting.http12.message.DefaultHttpHeaders; import org.apache.dubbo.remoting.http12.netty4.NettyHttpHeaders; -import java.io.OutputStream; import java.net.SocketAddress; -import io.netty.buffer.ByteBufInputStream; -import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler.Sharable; @@ -78,8 +76,7 @@ private void pingReceived(ChannelHandlerContext ctx) { @Override protected void channelRead(ChannelHandlerContext ctx, Http3DataFrame frame) { - ctx.fireChannelRead( - new Http2InputMessageFrame(getStreamId(ctx), new ByteBufInputStream(frame.content(), true), false)); + ctx.fireChannelRead(new Http2InputMessageFrame<>(getStreamId(ctx), frame.content(), false)); } private static long getStreamId(ChannelHandlerContext ctx) { @@ -88,7 +85,7 @@ private static long getStreamId(ChannelHandlerContext ctx) { @Override protected void channelInputClosed(ChannelHandlerContext ctx) { - ctx.fireChannelRead(new Http2InputMessageFrame(getStreamId(ctx), StreamUtils.EMPTY, true)); + ctx.fireChannelRead(new Http2InputMessageFrame<>(getStreamId(ctx), Unpooled.EMPTY_BUFFER, true)); } @Override @@ -111,16 +108,14 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) new DefaultHttp3HeadersFrame(((NettyHttpHeaders) headers.headers()).getHeaders()), promise); } else if (msg instanceof Http2OutputMessage) { - Http2OutputMessage message = (Http2OutputMessage) msg; - OutputStream body = message.getBody(); - assert body instanceof ByteBufOutputStream || body == null; + Http2OutputMessage message = (Http2OutputMessage) msg; + ByteBuf body = message.getBody(); if (message.isEndStream()) { if (body == null) { ctx.close(promise); return; } - ChannelFuture future = - ctx.write(new DefaultHttp3DataFrame(((ByteBufOutputStream) body).buffer()), ctx.newPromise()); + ChannelFuture future = ctx.write(new DefaultHttp3DataFrame(body), ctx.newPromise()); if (future.isDone()) { ctx.close(promise); } else { @@ -132,7 +127,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) promise.trySuccess(); return; } - ctx.write(new DefaultHttp3DataFrame(((ByteBufOutputStream) body).buffer()), promise); + ctx.write(new DefaultHttp3DataFrame(body), promise); } else { ctx.write(msg, promise); } diff --git a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3ProtocolSelectorHandler.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3ProtocolSelectorHandler.java index 9c14ddb0049d..4a9ab641ffbc 100644 --- a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3ProtocolSelectorHandler.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3ProtocolSelectorHandler.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.remoting.http12.HttpMetadata; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.command.HttpWriteQueue; import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; @@ -27,6 +28,7 @@ import org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory; import org.apache.dubbo.rpc.model.FrameworkModel; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; @@ -52,16 +54,17 @@ protected void channelRead0(ChannelHandlerContext ctx, HttpMetadata metadata) { throw new UnsupportedMediaTypeException(contentType); } - H2StreamChannel streamChannel = new NettyHttp3StreamChannel((QuicStreamChannel) ctx.channel()); + H2StreamChannel streamChannel = new NettyHttp3StreamChannel((QuicStreamChannel) ctx.channel()); HttpWriteQueueHandler writeQueueHandler = ctx.channel().pipeline().get(HttpWriteQueueHandler.class); if (writeQueueHandler != null) { - HttpWriteQueue writeQueue = writeQueueHandler.getWriteQueue(); - streamChannel = new Http2WriteQueueChannel(streamChannel, writeQueue); + HttpWriteQueue writeQueue = writeQueueHandler.getWriteQueue(); + streamChannel = new Http2WriteQueueChannel<>(streamChannel, writeQueue); } ChannelPipeline pipeline = ctx.pipeline(); - pipeline.addLast( - new NettyHttp2FrameHandler(streamChannel, factory.newInstance(streamChannel, url, frameworkModel))); + pipeline.addLast(new NettyHttp2FrameHandler( + streamChannel, + factory.newInstance(streamChannel, url, frameworkModel, new MessageTypeToken() {}))); pipeline.remove(this); ctx.fireChannelRead(metadata); } diff --git a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3StreamChannel.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3StreamChannel.java index dc3fb94283cb..08c05a488703 100644 --- a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3StreamChannel.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3StreamChannel.java @@ -27,10 +27,9 @@ import java.util.concurrent.CompletableFuture; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufOutputStream; import io.netty.handler.codec.quic.QuicStreamChannel; -public class NettyHttp3StreamChannel implements H2StreamChannel { +public class NettyHttp3StreamChannel implements H2StreamChannel { private final QuicStreamChannel http3StreamChannel; @@ -46,9 +45,8 @@ public CompletableFuture writeResetFrame(long errorCode) { } @Override - public Http2OutputMessage newOutputMessage(boolean endStream) { - ByteBuf buffer = http3StreamChannel.alloc().buffer(); - return new Http2OutputMessageFrame(new ByteBufOutputStream(buffer), endStream); + public Http2OutputMessage newOutputMessage(boolean endStream) { + return new Http2OutputMessageFrame<>(http3StreamChannel.alloc().buffer(), endStream); } @Override @@ -59,7 +57,7 @@ public CompletableFuture writeHeader(HttpMetadata httpMetadata) { } @Override - public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { NettyHttpChannelFutureListener futureListener = new NettyHttpChannelFutureListener(); http3StreamChannel.write(httpOutputMessage).addListener(futureListener); return futureListener; diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentByteBuf.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentByteBuf.java new file mode 100644 index 000000000000..0ec642dd6bd4 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentByteBuf.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.websocket; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.WrappedByteBuf; + +public class FinalFragmentByteBuf extends WrappedByteBuf implements FinalFragment { + + private final boolean finalFragment; + + public FinalFragmentByteBuf(ByteBuf buf, boolean finalFragment) { + super(buf); + this.finalFragment = finalFragment; + } + + @Override + public boolean isFinalFragment() { + return finalFragment; + } +} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentStreamingDecoder.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentStreamingDecoder.java index d5530171186d..65433b971013 100644 --- a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentStreamingDecoder.java +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentStreamingDecoder.java @@ -16,15 +16,16 @@ */ package org.apache.dubbo.remoting.websocket; -import org.apache.dubbo.remoting.http12.CompositeInputStream; import org.apache.dubbo.remoting.http12.exception.DecodeException; import org.apache.dubbo.remoting.http12.message.StreamingDecoder; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; -public class FinalFragmentStreamingDecoder implements StreamingDecoder { +import io.netty.buffer.ByteBuf; +import io.netty.buffer.CompositeByteBuf; +import io.netty.buffer.Unpooled; + +public class FinalFragmentStreamingDecoder implements StreamingDecoder { private boolean inDelivery; @@ -34,21 +35,21 @@ public class FinalFragmentStreamingDecoder implements StreamingDecoder { private boolean closing; - protected final CompositeInputStream accumulate = new CompositeInputStream(); + protected final CompositeByteBuf accumulate = Unpooled.compositeBuffer(); - protected FragmentListener listener; + protected FragmentListener listener; @Override public void request(int numMessages) {} @Override - public void decode(InputStream inputStream) throws DecodeException { + public void decode(ByteBuf buffer) throws DecodeException { if (closing || closed) { // ignored return; } - accumulate.addInputStream(inputStream); - if (inputStream instanceof FinalFragment && ((FinalFragment) inputStream).isFinalFragment()) { + accumulate.addComponent(true, buffer); + if (buffer instanceof FinalFragmentByteBuf && ((FinalFragmentByteBuf) buffer).isFinalFragment()) { pendingDelivery = true; deliver(); } @@ -66,15 +67,12 @@ public void onStreamClosed() { return; } closed = true; - try { - accumulate.close(); - } catch (IOException e) { - throw new DecodeException(e); - } + accumulate.clear(); + accumulate.release(); } @Override - public void setFragmentListener(FragmentListener listener) { + public void setFragmentListener(FragmentListener listener) { this.listener = listener; } @@ -91,13 +89,13 @@ private void deliver() { processBody(); pendingDelivery = false; } - if (closing) { - if (!closed) { - closed = true; - accumulate.close(); - listener.onClose(); - } + if (closing && !closed) { + closed = true; + accumulate.clear(); + accumulate.release(); + listener.onClose(); } + } catch (IOException e) { throw new DecodeException(e); } finally { @@ -106,18 +104,10 @@ private void deliver() { } private void processBody() throws IOException { - byte[] rawMessage = readRawMessage(accumulate, accumulate.available()); - InputStream inputStream = new ByteArrayInputStream(rawMessage); - invokeListener(inputStream); - } - - protected void invokeListener(InputStream inputStream) { - this.listener.onFragmentMessage(inputStream); + invokeListener(accumulate); } - protected byte[] readRawMessage(InputStream inputStream, int length) throws IOException { - byte[] data = new byte[length]; - inputStream.read(data, 0, length); - return data; + protected void invokeListener(ByteBuf buffer) { + this.listener.onFragmentMessage(buffer); } } diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketServerTransportListenerFactory.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketServerTransportListenerFactory.java index 94ea29f9a3ce..b1bf582190bd 100644 --- a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketServerTransportListenerFactory.java +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketServerTransportListenerFactory.java @@ -19,11 +19,16 @@ 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.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.rpc.model.FrameworkModel; @SPI(scope = ExtensionScope.FRAMEWORK) public interface WebSocketServerTransportListenerFactory { - WebSocketTransportListener newInstance(H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel); + WebSocketTransportListener newInstance( + H2StreamChannel streamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken); } diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketTransportListener.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketTransportListener.java index 09fb6ba47cf4..dfffb17e83e3 100644 --- a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketTransportListener.java +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketTransportListener.java @@ -18,4 +18,4 @@ import org.apache.dubbo.remoting.http12.h2.Http2TransportListener; -public interface WebSocketTransportListener extends Http2TransportListener {} +public interface WebSocketTransportListener extends Http2TransportListener {} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/NettyWebSocketChannel.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/NettyWebSocketChannel.java index 261687562c8c..f8060ad785c4 100644 --- a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/NettyWebSocketChannel.java +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/NettyWebSocketChannel.java @@ -19,7 +19,6 @@ import org.apache.dubbo.config.nested.TripleConfig; import org.apache.dubbo.remoting.http12.HttpMetadata; import org.apache.dubbo.remoting.http12.HttpOutputMessage; -import org.apache.dubbo.remoting.http12.LimitedByteBufOutputStream; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2OutputMessage; import org.apache.dubbo.remoting.http12.h2.Http2OutputMessageFrame; @@ -28,9 +27,10 @@ import java.net.SocketAddress; import java.util.concurrent.CompletableFuture; +import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; -public class NettyWebSocketChannel implements H2StreamChannel { +public class NettyWebSocketChannel implements H2StreamChannel { private final Channel channel; @@ -49,11 +49,8 @@ public CompletableFuture writeResetFrame(long errorCode) { } @Override - public Http2OutputMessage newOutputMessage(boolean endStream) { - return new Http2OutputMessageFrame( - new LimitedByteBufOutputStream( - channel.alloc().buffer(), tripleConfig.getMaxResponseBodySizeOrDefault()), - endStream); + public Http2OutputMessage newOutputMessage(boolean endStream) { + return new Http2OutputMessageFrame<>(channel.alloc().buffer(), endStream); } @Override @@ -64,7 +61,7 @@ public CompletableFuture writeHeader(HttpMetadata httpMetadata) { } @Override - public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { NettyHttpChannelFutureListener futureListener = new NettyHttpChannelFutureListener(); channel.write(httpOutputMessage).addListener(futureListener); return futureListener; diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketFrameCodec.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketFrameCodec.java index 0bf25d1dac43..10de2509c090 100644 --- a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketFrameCodec.java +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketFrameCodec.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.remoting.websocket.netty4; -import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.HttpHeaderNames; import org.apache.dubbo.remoting.http12.HttpHeaders; @@ -28,15 +27,13 @@ import org.apache.dubbo.remoting.http12.h2.Http2MetadataFrame; import org.apache.dubbo.remoting.http12.h2.Http2OutputMessage; import org.apache.dubbo.remoting.http12.netty4.h1.NettyHttp1HttpHeaders; -import org.apache.dubbo.remoting.websocket.FinalFragmentByteBufInputStream; +import org.apache.dubbo.remoting.websocket.FinalFragmentByteBuf; import org.apache.dubbo.remoting.websocket.WebSocketHeaderNames; -import java.io.IOException; -import java.io.OutputStream; import java.util.List; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.Unpooled; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; @@ -53,7 +50,7 @@ public class WebSocketFrameCodec extends ChannelDuplexHandler { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof BinaryWebSocketFrame || msg instanceof TextWebSocketFrame) { - Http2InputMessage http2InputMessage = onDataFrame((WebSocketFrame) msg); + Http2InputMessage http2InputMessage = onDataFrame((WebSocketFrame) msg); super.channelRead(ctx, http2InputMessage); } else if (msg instanceof CloseWebSocketFrame) { Object closeMessage = onCloseFrame((CloseWebSocketFrame) msg); @@ -63,10 +60,11 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception } } + @SuppressWarnings("unchecked") @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { if (msg instanceof Http2OutputMessage) { - WebSocketFrame webSocketFrame = encodeWebSocketFrame(ctx, (Http2OutputMessage) msg); + WebSocketFrame webSocketFrame = encodeWebSocketFrame((Http2OutputMessage) msg); super.write(ctx, webSocketFrame, promise); } else if (msg instanceof Http2Header) { Http2Header http2Header = (Http2Header) msg; @@ -96,17 +94,16 @@ private Http2Header onHandshakeComplete(WebSocketServerProtocolHandler.Handshake return new Http2MetadataFrame(httpHeaders); } - private Http2InputMessageFrame onDataFrame(WebSocketFrame webSocketFrame) { + private Http2InputMessageFrame onDataFrame(WebSocketFrame webSocketFrame) { ByteBuf data = webSocketFrame.content(); - return new Http2InputMessageFrame( - new FinalFragmentByteBufInputStream(data, true, webSocketFrame.isFinalFragment()), false); + return new Http2InputMessageFrame<>(new FinalFragmentByteBuf(data, webSocketFrame.isFinalFragment()), false); } private Object onCloseFrame(CloseWebSocketFrame closeWebSocketFrame) { if (closeWebSocketFrame.statusCode() != WebSocketCloseStatus.NORMAL_CLOSURE.code()) { return new DefaultHttp2ResetFrame(closeWebSocketFrame.statusCode()); } - return new Http2InputMessageFrame(StreamUtils.EMPTY, true); + return new Http2InputMessageFrame<>(Unpooled.EMPTY_BUFFER, true); } private CloseWebSocketFrame encodeCloseWebSocketFrame(Http2Header http2Header) { @@ -125,16 +122,8 @@ private CloseWebSocketFrame encodeCloseWebSocketFrame(Http2Header http2Header) { return new CloseWebSocketFrame(status); } - private WebSocketFrame encodeWebSocketFrame(ChannelHandlerContext ctx, Http2OutputMessage outputMessage) - throws IOException { - OutputStream body = outputMessage.getBody(); - if (body == null) { - return new BinaryWebSocketFrame(); - } - if (body instanceof ByteBufOutputStream) { - ByteBuf buffer = ((ByteBufOutputStream) body).buffer(); - return new BinaryWebSocketFrame(buffer); - } - throw new IllegalArgumentException("Http2OutputMessage body must be ByteBufOutputStream"); + private WebSocketFrame encodeWebSocketFrame(Http2OutputMessage outputMessage) { + ByteBuf body = outputMessage.getBody(); + return new BinaryWebSocketFrame(body); } } diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketProtocolSelectorHandler.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketProtocolSelectorHandler.java index 1ac8bfbdb98c..b251020989d4 100644 --- a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketProtocolSelectorHandler.java +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketProtocolSelectorHandler.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.config.nested.TripleConfig; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.command.HttpWriteQueue; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.command.Http2WriteQueueChannel; @@ -27,6 +28,7 @@ import org.apache.dubbo.remoting.websocket.WebSocketTransportListener; import org.apache.dubbo.rpc.model.FrameworkModel; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.FullHttpRequest; @@ -54,14 +56,15 @@ public WebSocketProtocolSelectorHandler( @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) { - H2StreamChannel streamChannel = new NettyWebSocketChannel(ctx.channel(), tripleConfig); + H2StreamChannel streamChannel = new NettyWebSocketChannel(ctx.channel(), tripleConfig); HttpWriteQueueHandler writeQueueHandler = ctx.channel().pipeline().get(HttpWriteQueueHandler.class); if (writeQueueHandler != null) { - HttpWriteQueue writeQueue = writeQueueHandler.getWriteQueue(); - streamChannel = new Http2WriteQueueChannel(streamChannel, writeQueue); + HttpWriteQueue writeQueue = writeQueueHandler.getWriteQueue(); + streamChannel = new Http2WriteQueueChannel<>(streamChannel, writeQueue); } - WebSocketTransportListener webSocketTransportListener = - defaultWebSocketServerTransportListenerFactory.newInstance(streamChannel, url, frameworkModel); + WebSocketTransportListener webSocketTransportListener = + defaultWebSocketServerTransportListenerFactory.newInstance( + streamChannel, url, frameworkModel, new MessageTypeToken() {}); ctx.channel().closeFuture().addListener(future -> webSocketTransportListener.close()); ctx.pipeline() .addLast(new NettyHttp2FrameHandler(streamChannel, webSocketTransportListener)) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufInputMessageHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufInputMessageHandler.java new file mode 100644 index 000000000000..b3825131e9c5 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufInputMessageHandler.java @@ -0,0 +1,61 @@ +/* + * 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.remoting.http12.HttpInputMessage; +import org.apache.dubbo.remoting.http12.message.DefaultByteBufListeningDecoder; +import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder; +import org.apache.dubbo.remoting.http12.message.ListeningDecoder; +import org.apache.dubbo.remoting.http12.message.NettyStreamingDecoder; +import org.apache.dubbo.remoting.http12.message.StreamingDecoder; +import org.apache.dubbo.remoting.http12.netty4.EmptyByteBufMessage; +import org.apache.dubbo.rpc.model.MethodDescriptor; +import org.apache.dubbo.rpc.model.ServiceDescriptor; + +import java.io.IOException; + +import io.netty.buffer.ByteBuf; + +public class ByteBufInputMessageHandler implements InputMessageHandler { + + @Override + public StreamingDecoder createStreamingDecoder() { + return new NettyStreamingDecoder(); + } + + @Override + public ListeningDecoder createListeningDecoder( + HttpMessageDecoder httpMessageDecoder, Class[] targetTypes) { + return new DefaultByteBufListeningDecoder(httpMessageDecoder, targetTypes); + } + + @Override + public MethodDescriptor findMethodDescriptor( + ServiceDescriptor serviceDescriptor, String methodName, ByteBuf rawMessage) throws IOException { + return DescriptorUtils.findTripleMethodDescriptor(serviceDescriptor, methodName, rawMessage); + } + + @Override + public String supportProtocol() { + return "http"; + } + + @Override + public HttpInputMessage empty() { + return EmptyByteBufMessage.INSTANCE; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufOutputMessageHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufOutputMessageHandler.java new file mode 100644 index 000000000000..33c235b949dd --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufOutputMessageHandler.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; + +import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.message.ByteBufResponseEncoder; +import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import org.apache.dubbo.remoting.http12.message.ResponseEncoder; +import org.apache.dubbo.remoting.http12.netty4.EmptyByteBufMessage; + +import io.netty.buffer.ByteBuf; + +public class ByteBufOutputMessageHandler implements OutputMessageHandler { + + @Override + public ResponseEncoder createResponseEncoder(HttpMessageEncoder messageEncoder) { + return new ByteBufResponseEncoder(messageEncoder); + } + + @Override + public HttpOutputMessage empty() { + return EmptyByteBufMessage.INSTANCE; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/Deframer.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufPack.java similarity index 51% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/Deframer.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufPack.java index 59083e9a2419..a58c969248f7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/Deframer.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufPack.java @@ -14,32 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.frame; +package org.apache.dubbo.rpc.protocol.tri; -import io.netty.buffer.ByteBuf; - -public interface Deframer { +import org.apache.dubbo.rpc.model.Pack; - /** - * Adds the given data to this deframer and attempts delivery to the listener. - * - * @param data the raw data read from the remote endpoint. Must be non-null. - */ - void deframe(ByteBuf data); +import io.netty.buffer.ByteBuf; - /** - * Requests up to the given number of messages from the call. No additional messages will be - * delivered. - * - *

If {@link #close()} has been called, this method will have no effect. - * - * @param numMessages the requested number of messages to be delivered to the listener. - */ - void request(int numMessages); +public interface ByteBufPack extends Pack { /** - * Closes this deframer and frees any resources. After this method is called, additional calls - * will have no effect. + * @param buffer byte buffer + * @param obj instance + * @throws Exception when error occurs */ - void close(); + default void pack(ByteBuf buffer, Object obj) throws Exception { + byte[] data = pack(obj); + buffer.writeBytes(data); + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufPackableMethod.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufPackableMethod.java new file mode 100644 index 000000000000..cbfcb0c435b7 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufPackableMethod.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.rpc.protocol.tri; + +import org.apache.dubbo.rpc.model.PackableMethod; + +import io.netty.buffer.ByteBuf; + +public interface ByteBufPackableMethod extends PackableMethod { + + default Object parseRequest(ByteBuf buffer) throws Exception { + return getRequestUnpack().unpack(buffer); + } + + default Object parseResponse(ByteBuf data) throws Exception { + return parseResponse(data, false); + } + + default Object parseResponse(ByteBuf data, boolean isReturnTriException) throws Exception { + ByteBufUnPack unPack = getResponseUnpack(); + if (unPack instanceof ByteBufWrapperUnPack) { + return ((ByteBufWrapperUnPack) unPack).unpack(data, isReturnTriException); + } + return unPack.unpack(data); + } + + default void packRequest(ByteBuf buffer, Object request) throws Exception { + getRequestPack().pack(request); + } + + default void packResponse(ByteBuf buffer, Object response) throws Exception { + getResponsePack().pack(buffer, response); + } + + ByteBufPack getRequestPack(); + + ByteBufPack getResponsePack(); + + ByteBufUnPack getResponseUnpack(); + + ByteBufUnPack getRequestUnpack(); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufUnPack.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufUnPack.java new file mode 100644 index 000000000000..5e9f96e7e7aa --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufUnPack.java @@ -0,0 +1,39 @@ +/* + * 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.rpc.model.UnPack; + +import io.netty.buffer.ByteBuf; + +public interface ByteBufUnPack extends UnPack { + + /** + * @param buffer direct byte buffer + * @return object instance + * @throws Exception exception + */ + default Object unpack(ByteBuf buffer) throws Exception { + if (buffer.hasArray()) { + return unpack(buffer.array()); + } else { + byte[] bytes = new byte[buffer.readableBytes()]; + buffer.readBytes(bytes); + return unpack(bytes); + } + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufWrapperUnPack.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufWrapperUnPack.java new file mode 100644 index 000000000000..40845fa8b9cb --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ByteBufWrapperUnPack.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; + +import io.netty.buffer.ByteBuf; + +public interface ByteBufWrapperUnPack { + + default Object unpack(ByteBuf data) throws Exception { + return unpack(data, false); + } + + Object unpack(ByteBuf data, boolean isReturnTriException) throws Exception; +} 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 index 91c09aa00981..b84973a25cb5 100644 --- 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 @@ -34,6 +34,8 @@ import java.util.Arrays; import java.util.List; +import io.netty.buffer.ByteBuf; + /** * The MetaUtils provides utility methods for working with service descriptors and method descriptors. */ @@ -126,6 +128,28 @@ public static MethodDescriptor findReflectionMethodDescriptor( return methodDescriptor; } + public static MethodDescriptor findTripleMethodDescriptor( + ServiceDescriptor serviceDescriptor, String methodName, ByteBuf rawMessage) { + MethodDescriptor methodDescriptor = findReflectionMethodDescriptor(serviceDescriptor, methodName); + if (methodDescriptor == null) { + List methodDescriptors = serviceDescriptor.getMethods(methodName); + TripleRequestWrapper request = TripleRequestWrapper.parseFrom(rawMessage.nioBuffer()); + 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; + } + public static MethodDescriptor findTripleMethodDescriptor( ServiceDescriptor serviceDescriptor, String methodName, InputStream rawMessage) throws IOException { MethodDescriptor methodDescriptor = findReflectionMethodDescriptor(serviceDescriptor, methodName); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/InputMessageHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/InputMessageHandler.java new file mode 100644 index 000000000000..02d78cbd48fb --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/InputMessageHandler.java @@ -0,0 +1,43 @@ +/* + * 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.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.remoting.http12.HttpInputMessage; +import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder; +import org.apache.dubbo.remoting.http12.message.ListeningDecoder; +import org.apache.dubbo.remoting.http12.message.StreamingDecoder; +import org.apache.dubbo.rpc.model.MethodDescriptor; +import org.apache.dubbo.rpc.model.ServiceDescriptor; + +import java.io.IOException; + +@SPI(scope = ExtensionScope.FRAMEWORK) +public interface InputMessageHandler { + + StreamingDecoder createStreamingDecoder(); + + ListeningDecoder createListeningDecoder(HttpMessageDecoder httpMessageDecoder, Class[] targetTypes); + + MethodDescriptor findMethodDescriptor(ServiceDescriptor serviceDescriptor, String methodName, INPUT rawMessage) + throws IOException; + + String supportProtocol(); + + HttpInputMessage empty(); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/InputStreamMessageHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/InputStreamMessageHandler.java new file mode 100644 index 000000000000..f3f2950b9aef --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/InputStreamMessageHandler.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.rpc.protocol.tri; + +import org.apache.dubbo.remoting.http12.EmptyInputStreamMessage; +import org.apache.dubbo.remoting.http12.HttpInputMessage; +import org.apache.dubbo.remoting.http12.message.DefaultListeningDecoder; +import org.apache.dubbo.remoting.http12.message.DefaultStreamingDecoder; +import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder; +import org.apache.dubbo.remoting.http12.message.ListeningDecoder; +import org.apache.dubbo.remoting.http12.message.StreamingDecoder; +import org.apache.dubbo.rpc.model.MethodDescriptor; +import org.apache.dubbo.rpc.model.ServiceDescriptor; + +import java.io.IOException; +import java.io.InputStream; + +public class InputStreamMessageHandler implements InputMessageHandler { + + @Override + public StreamingDecoder createStreamingDecoder() { + return new DefaultStreamingDecoder(); + } + + @Override + public ListeningDecoder createListeningDecoder( + HttpMessageDecoder httpMessageDecoder, Class[] targetTypes) { + return new DefaultListeningDecoder(httpMessageDecoder, targetTypes); + } + + @Override + public MethodDescriptor findMethodDescriptor( + ServiceDescriptor serviceDescriptor, String methodName, InputStream rawMessage) throws IOException { + return DescriptorUtils.findTripleMethodDescriptor(serviceDescriptor, methodName, rawMessage); + } + + @Override + public String supportProtocol() { + return "http"; + } + + @Override + public HttpInputMessage empty() { + return EmptyInputStreamMessage.INSTANCE; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/MessageHandlerRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/MessageHandlerRegistry.java new file mode 100644 index 000000000000..8f6cc092ded5 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/MessageHandlerRegistry.java @@ -0,0 +1,67 @@ +/* + * 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.utils.CollectionUtils; +import org.apache.dubbo.common.utils.TypeUtils; +import org.apache.dubbo.rpc.model.FrameworkModel; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class MessageHandlerRegistry { + + private final Map, Map>> inputHandlers = new ConcurrentHashMap<>(); + private final Map, OutputMessageHandler> outputHandlers = new ConcurrentHashMap<>(); + + public MessageHandlerRegistry(FrameworkModel frameworkModel) { + frameworkModel + .getExtensionLoader(InputMessageHandler.class) + .getSupportedExtensionInstances() + .forEach(this::register); + frameworkModel + .getExtensionLoader(OutputMessageHandler.class) + .getSupportedExtensionInstances() + .forEach(this::register); + } + + public void register(InputMessageHandler handler) { + Class inputType = TypeUtils.findActualTypeArgument(handler.getClass(), InputMessageHandler.class, 0); + inputHandlers + .computeIfAbsent(inputType, clazz -> new ConcurrentHashMap<>()) + .put(handler.supportProtocol(), handler); + } + + public void register(OutputMessageHandler handler) { + Class outputType = TypeUtils.findActualTypeArgument(handler.getClass(), OutputMessageHandler.class, 0); + outputHandlers.put(outputType, handler); + } + + @SuppressWarnings("unchecked") + public InputMessageHandler get(Class inputType, String protocol) { + Map> inputMessageHandlerMap = inputHandlers.get(inputType); + if (CollectionUtils.isEmptyMap(inputMessageHandlerMap)) { + return null; + } + return (InputMessageHandler) inputMessageHandlerMap.get(protocol); + } + + @SuppressWarnings("unchecked") + public OutputMessageHandler get(Class outputType) { + return (OutputMessageHandler) outputHandlers.get(outputType); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/OutputMessageHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/OutputMessageHandler.java new file mode 100644 index 000000000000..212bc25a98b5 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/OutputMessageHandler.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; + +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import org.apache.dubbo.remoting.http12.message.ResponseEncoder; + +@SPI(scope = ExtensionScope.FRAMEWORK) +public interface OutputMessageHandler { + + ResponseEncoder createResponseEncoder(HttpMessageEncoder messageEncoder); + + HttpOutputMessage empty(); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/OutputStreamMessageHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/OutputStreamMessageHandler.java new file mode 100644 index 000000000000..6ba7037319bf --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/OutputStreamMessageHandler.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; + +import org.apache.dubbo.remoting.http12.EmptyOutputStreamMessage; +import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import org.apache.dubbo.remoting.http12.message.OutputStreamResponseEncoder; +import org.apache.dubbo.remoting.http12.message.ResponseEncoder; + +import java.io.OutputStream; + +public class OutputStreamMessageHandler implements OutputMessageHandler { + + @Override + public ResponseEncoder createResponseEncoder(HttpMessageEncoder messageEncoder) { + return new OutputStreamResponseEncoder(messageEncoder); + } + + @Override + public HttpOutputMessage empty() { + return EmptyOutputStreamMessage.INSTANCE; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleCustomerProtocolWrapper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleCustomerProtocolWrapper.java index 7b57a71d253a..9b8ecda96c16 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleCustomerProtocolWrapper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleCustomerProtocolWrapper.java @@ -229,8 +229,11 @@ public List getArgTypes() { public TripleRequestWrapper() {} public static TripleRequestWrapper parseFrom(byte[] data) { + return parseFrom(ByteBuffer.wrap(data)); + } + + public static TripleRequestWrapper parseFrom(ByteBuffer byteBuffer) { TripleRequestWrapper tripleRequestWrapper = new TripleRequestWrapper(); - ByteBuffer byteBuffer = ByteBuffer.wrap(data); tripleRequestWrapper.args = new ArrayList<>(); tripleRequestWrapper.argTypes = new ArrayList<>(); while (byteBuffer.position() < byteBuffer.limit()) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/TripleClientCall.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/TripleClientCall.java index 99651914974b..bff5b35e7431 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/TripleClientCall.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/TripleClientCall.java @@ -22,11 +22,13 @@ import org.apache.dubbo.remoting.api.connection.AbstractConnectionClient; import org.apache.dubbo.rpc.TriRpcStatus; import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.ByteBufPackableMethod; import org.apache.dubbo.rpc.protocol.tri.RequestMetadata; 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.ClientCallToObserverAdapter; import org.apache.dubbo.rpc.protocol.tri.stream.ClientStream; +import org.apache.dubbo.rpc.protocol.tri.stream.ClientStream.Listener; import org.apache.dubbo.rpc.protocol.tri.stream.ClientStreamFactory; import org.apache.dubbo.rpc.protocol.tri.stream.StreamUtils; import org.apache.dubbo.rpc.protocol.tri.transport.TripleWriteQueue; @@ -34,6 +36,8 @@ import java.util.Map; import java.util.concurrent.Executor; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; import io.netty.handler.codec.http2.Http2Exception.StreamException; import static io.netty.handler.codec.http2.Http2Error.FLOW_CONTROL_ERROR; @@ -41,7 +45,7 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_SERIALIZE_TRIPLE; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_STREAM_LISTENER; -public class TripleClientCall implements ClientCall, ClientStream.Listener { +public class TripleClientCall implements ClientCall, Listener { private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(TripleClientCall.class); private final AbstractConnectionClient connectionClient; private final Executor executor; @@ -49,7 +53,7 @@ public class TripleClientCall implements ClientCall, ClientStream.Listener { private final TripleWriteQueue writeQueue; private RequestMetadata requestMetadata; private ClientStream stream; - private ClientCall.Listener listener; + private Listener listener; private boolean canceled; private boolean headerSent; private boolean autoRequest = true; @@ -69,7 +73,7 @@ public TripleClientCall( // stream listener start @Override - public void onMessage(byte[] message, boolean isReturnTriException) { + public void onMessage(ByteBuf message, boolean isReturnTriException) { if (done) { LOGGER.warn( PROTOCOL_STREAM_LISTENER, @@ -81,8 +85,17 @@ public void onMessage(byte[] message, boolean isReturnTriException) { return; } try { - Object unpacked = requestMetadata.packableMethod.parseResponse(message, isReturnTriException); - listener.onMessage(unpacked, message.length); + int contentLength = message.readableBytes(); + Object unpacked; + if (requestMetadata.packableMethod instanceof ByteBufPackableMethod) { + unpacked = ((ByteBufPackableMethod) requestMetadata.packableMethod) + .parseResponse(message, isReturnTriException); + } else { + byte[] data = new byte[contentLength]; + message.readBytes(data); + unpacked = requestMetadata.packableMethod.parseResponse(data, isReturnTriException); + } + listener.onMessage(unpacked, contentLength); } catch (Throwable t) { TriRpcStatus status = TriRpcStatus.INTERNAL .withDescription("Deserialize response failed") @@ -194,17 +207,16 @@ public void sendMessage(Object message) { headerSent = true; stream.sendHeader(requestMetadata.toHeaders()); } - final byte[] data; + ByteBuf buffer = allocate(); try { - data = requestMetadata.packableMethod.packRequest(message); - int compressed = Identity.MESSAGE_ENCODING.equals(requestMetadata.compressor.getMessageEncoding()) ? 0 : 1; - final byte[] compress = requestMetadata.compressor.compress(data); - stream.sendMessage(compress, compressed).addListener(f -> { + ByteBuf messageBuffer = prepareMessageBuffer(buffer, message); + stream.sendMessage(messageBuffer).addListener(f -> { if (!f.isSuccess()) { cancelByLocal(f.cause()); } }); } catch (Throwable t) { + buffer.release(); LOGGER.error( PROTOCOL_FAILED_SERIALIZE_TRIPLE, "", @@ -224,6 +236,33 @@ public void sendMessage(Object message) { } // stream listener end + private ByteBuf prepareMessageBuffer(ByteBuf buffer, Object message) throws Exception { + boolean isIdentityEncoding = Identity.MESSAGE_ENCODING.equals(requestMetadata.compressor.getMessageEncoding()); + ByteBuf targetBuffer = isIdentityEncoding ? buffer : allocate(); + + targetBuffer.writeByte(isIdentityEncoding ? 0 : 1); + int position = targetBuffer.writerIndex(); + targetBuffer.writerIndex(position + 4); + + packRequest(buffer, message); + + if (!isIdentityEncoding) { + requestMetadata.compressor.compress(buffer, targetBuffer); + } + int len = targetBuffer.writerIndex() - position - 4; + targetBuffer.setInt(position, len); + return targetBuffer; + } + + private void packRequest(ByteBuf buffer, Object message) throws Exception { + if (requestMetadata.packableMethod instanceof ByteBufPackableMethod) { + ((ByteBufPackableMethod) requestMetadata.packableMethod).packRequest(buffer, message); + } else { + byte[] data = requestMetadata.packableMethod.packRequest(message); + buffer.writeBytes(data); + } + } + @Override public void halfClose() { if (!headerSent) { @@ -245,7 +284,7 @@ public void setCompression(String compression) { } @Override - public StreamObserver start(RequestMetadata metadata, ClientCall.Listener responseListener) { + public StreamObserver start(RequestMetadata metadata, Listener responseListener) { ClientStream stream; for (ClientStreamFactory factory : frameworkModel.getActivateExtensions(ClientStreamFactory.class)) { stream = factory.createClientStream(connectionClient, frameworkModel, executor, this, writeQueue); @@ -268,4 +307,8 @@ public boolean isAutoRequest() { public void setAutoRequest(boolean autoRequest) { this.autoRequest = autoRequest; } + + private ByteBuf allocate() { + return this.connectionClient.getChannel(true).alloc().buffer(); + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/command/DataQueueCommand.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/command/DataQueueCommand.java index a9ef447abb4d..5cd2505672f1 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/command/DataQueueCommand.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/command/DataQueueCommand.java @@ -25,23 +25,19 @@ public class DataQueueCommand extends StreamQueueCommand { - private final byte[] data; - - private final int compressFlag; + private final ByteBuf data; private final boolean endStream; - private DataQueueCommand( - TripleStreamChannelFuture streamChannelFuture, byte[] data, int compressFlag, boolean endStream) { + private DataQueueCommand(TripleStreamChannelFuture streamChannelFuture, ByteBuf data, boolean endStream) { super(streamChannelFuture); this.data = data; - this.compressFlag = compressFlag; this.endStream = endStream; } public static DataQueueCommand create( - TripleStreamChannelFuture streamChannelFuture, byte[] data, boolean endStream, int compressFlag) { - return new DataQueueCommand(streamChannelFuture, data, compressFlag, endStream); + TripleStreamChannelFuture streamChannelFuture, ByteBuf data, boolean endStream) { + return new DataQueueCommand(streamChannelFuture, data, endStream); } @Override @@ -49,16 +45,12 @@ public void doSend(ChannelHandlerContext ctx, ChannelPromise promise) { if (data == null) { ctx.write(new DefaultHttp2DataFrame(endStream), promise); } else { - ByteBuf buf = ctx.alloc().buffer(); - buf.writeByte(compressFlag); - buf.writeInt(data.length); - buf.writeBytes(data); - ctx.write(new DefaultHttp2DataFrame(buf, endStream), promise); + ctx.write(new DefaultHttp2DataFrame(data, endStream), promise); } } // for test - public byte[] getData() { + public ByteBuf getData() { return data; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Bzip2.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Bzip2.java index ab2c1bd3fec0..9789dbf1e5fa 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Bzip2.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Bzip2.java @@ -22,6 +22,9 @@ import java.io.IOException; import java.io.OutputStream; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; import org.apache.commons.io.output.ByteArrayOutputStream; @@ -68,6 +71,22 @@ public OutputStream decorate(OutputStream outputStream) { } } + @Override + public void compress(ByteBuf src, ByteBuf dst) { + byte[] input = new byte[src.readableBytes()]; + src.readBytes(input); + dst.ensureWritable(input.length); + + try (ByteBufOutputStream out = new ByteBufOutputStream(dst); + BZip2CompressorOutputStream bZip2CompressorOutputStream = new BZip2CompressorOutputStream(out)) { + bZip2CompressorOutputStream.write(input); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + src.release(); + } + } + @Override public byte[] decompress(byte[] payloadByteArr) { if (null == payloadByteArr || 0 == payloadByteArr.length) { @@ -88,4 +107,23 @@ public byte[] decompress(byte[] payloadByteArr) { } return out.toByteArray(); } + + @Override + public ByteBuf decompress(ByteBuf src) { + ByteBuf dst = src.alloc().ioBuffer(src.readableBytes() * 4); + try (ByteBufOutputStream out = new ByteBufOutputStream(dst); + ByteBufInputStream in = new ByteBufInputStream(src); + BZip2CompressorInputStream bZip2CompressorInputStream = new BZip2CompressorInputStream(in)) { + byte[] buffer = new byte[2048]; + int n; + while ((n = bZip2CompressorInputStream.read(buffer)) >= 0) { + out.write(buffer, 0, n); + } + return dst; + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + src.release(); + } + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Compressor.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Compressor.java index 4a67db5f6c07..d99b540f7b4b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Compressor.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Compressor.java @@ -23,6 +23,8 @@ import java.io.OutputStream; +import io.netty.buffer.ByteBuf; + /** * compress payload for grpc request, and decompress response payload Configure it in files, * pictures or other configurations that exist in the system properties Configure {@link @@ -53,4 +55,12 @@ static Compressor getCompressor(FrameworkModel frameworkModel, String compressor byte[] compress(byte[] payloadByteArr); OutputStream decorate(OutputStream outputStream); + + /** + * compress payload + * + * @param src payload byte buffer + * @param dst compressed payload byte buffer + */ + void compress(ByteBuf src, ByteBuf dst); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/CompressorConfigure.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/CompressorConfigure.java new file mode 100644 index 000000000000..c95fc2916262 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/CompressorConfigure.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.compressor; + +public interface CompressorConfigure { + + default void setCompressor(Compressor compressor) { + // no op + } + + default void setDeCompressor(DeCompressor deCompressor) { + // no op + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/DeCompressor.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/DeCompressor.java index c6ba092fb08e..3e2aec2c59c2 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/DeCompressor.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/DeCompressor.java @@ -20,6 +20,8 @@ import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.rpc.model.FrameworkModel; +import io.netty.buffer.ByteBuf; + @SPI(scope = ExtensionScope.FRAMEWORK) public interface DeCompressor extends MessageEncoding { @@ -42,4 +44,13 @@ static DeCompressor getCompressor(FrameworkModel frameworkModel, String compress * @return decompressed payload byte array */ byte[] decompress(byte[] payloadByteArr); + + /** + * decompress payload + * + * @param src payload byte buffer + * + * @return decompressed payload byte buffer + */ + ByteBuf decompress(ByteBuf src); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Gzip.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Gzip.java index 2623ded6b16e..66dc4df9cf89 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Gzip.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Gzip.java @@ -25,6 +25,10 @@ import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; + /** * gzip compressor */ @@ -62,6 +66,22 @@ public OutputStream decorate(OutputStream outputStream) { } } + @Override + public void compress(ByteBuf src, ByteBuf dst) { + byte[] input = new byte[src.readableBytes()]; + src.readBytes(input); + dst.ensureWritable(input.length); + + try (ByteBufOutputStream out = new ByteBufOutputStream(dst); + GZIPOutputStream gzipOutputStream = new GZIPOutputStream(out)) { + gzipOutputStream.write(input); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + src.release(); + } + } + @Override public byte[] decompress(byte[] payloadByteArr) throws RpcException { if (null == payloadByteArr || 0 == payloadByteArr.length) { @@ -82,4 +102,23 @@ public byte[] decompress(byte[] payloadByteArr) throws RpcException { return byteOutStream.toByteArray(); } + + @Override + public ByteBuf decompress(ByteBuf src) { + ByteBuf dst = src.alloc().ioBuffer(src.readableBytes() * 4); + try (ByteBufOutputStream out = new ByteBufOutputStream(dst); + ByteBufInputStream in = new ByteBufInputStream(src); + GZIPInputStream gzipInputStream = new GZIPInputStream(in)) { + byte[] buffer = new byte[2048]; + int n; + while ((n = gzipInputStream.read(buffer)) >= 0) { + out.write(buffer, 0, n); + } + return dst; + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + src.release(); + } + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Identity.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Identity.java index 93fdd9052111..303b5e335c1d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Identity.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Identity.java @@ -18,6 +18,8 @@ import java.io.OutputStream; +import io.netty.buffer.ByteBuf; + /** * Default compressor *

@@ -44,8 +46,18 @@ public OutputStream decorate(OutputStream outputStream) { return outputStream; } + @Override + public void compress(ByteBuf src, ByteBuf dst) { + // no op + } + @Override public byte[] decompress(byte[] payloadByteArr) { return payloadByteArr; } + + @Override + public ByteBuf decompress(ByteBuf src) { + return src; + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Snappy.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Snappy.java index 26427bcc2797..8af332b10dab 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Snappy.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/compressor/Snappy.java @@ -21,6 +21,8 @@ import java.io.IOException; import java.io.OutputStream; +import io.netty.buffer.ByteBuf; + /** * snappy compressor, Provide high-speed compression speed and reasonable compression ratio * @@ -52,6 +54,21 @@ public OutputStream decorate(OutputStream outputStream) { return outputStream; } + @Override + public void compress(ByteBuf src, ByteBuf dst) { + try { + int maxCompressedLength = org.xerial.snappy.Snappy.maxCompressedLength(src.readableBytes()); + dst.ensureWritable(maxCompressedLength); + int compressedSize = org.xerial.snappy.Snappy.compress( + src.nioBuffer(), dst.nioBuffer(dst.writerIndex(), maxCompressedLength)); + dst.writerIndex(dst.writerIndex() + compressedSize); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + src.release(); + } + } + @Override public byte[] decompress(byte[] payloadByteArr) { if (null == payloadByteArr || 0 == payloadByteArr.length) { @@ -64,4 +81,16 @@ public byte[] decompress(byte[] payloadByteArr) { throw new IllegalStateException(e); } } + + @Override + public ByteBuf decompress(ByteBuf src) { + try { + int uncompressedLength = org.xerial.snappy.Snappy.uncompressedLength(src.nioBuffer()); + ByteBuf dst = src.alloc().ioBuffer(uncompressedLength); + org.xerial.snappy.Snappy.uncompress(src.nioBuffer(), dst.nioBuffer()); + return dst; + } catch (IOException e) { + throw new IllegalStateException(e); + } + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoder.java deleted file mode 100644 index 6970203cf8cb..000000000000 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoder.java +++ /dev/null @@ -1,169 +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.frame; - -import org.apache.dubbo.rpc.RpcException; -import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.CompositeByteBuf; -import io.netty.buffer.Unpooled; - -public class TriDecoder implements Deframer { - - private static final int HEADER_LENGTH = 5; - private static final int COMPRESSED_FLAG_MASK = 1; - private static final int RESERVED_MASK = 0xFE; - private final CompositeByteBuf accumulate = Unpooled.compositeBuffer(); - private final Listener listener; - private final DeCompressor decompressor; - private boolean compressedFlag; - private long pendingDeliveries; - private boolean inDelivery = false; - private boolean closing; - private boolean closed; - - private int requiredLength = HEADER_LENGTH; - - private GrpcDecodeState state = GrpcDecodeState.HEADER; - - public TriDecoder(DeCompressor decompressor, Listener listener) { - this.decompressor = decompressor; - this.listener = listener; - } - - @Override - public void deframe(ByteBuf data) { - if (closing || closed) { - // ignored - return; - } - accumulate.addComponent(true, data); - deliver(); - } - - public void request(int numMessages) { - pendingDeliveries += numMessages; - deliver(); - } - - @Override - public void close() { - closing = true; - deliver(); - } - - private void deliver() { - // We can have reentrancy here when using a direct executor, triggered by calls to - // request more messages. This is safe as we simply loop until pendingDelivers = 0 - if (inDelivery) { - return; - } - inDelivery = true; - try { - // Process the uncompressed bytes. - while (pendingDeliveries > 0 && hasEnoughBytes()) { - switch (state) { - case HEADER: - processHeader(); - break; - case PAYLOAD: - // Read the body and deliver the message. - processBody(); - - // Since we've delivered a message, decrement the number of pending - // deliveries remaining. - pendingDeliveries--; - break; - default: - throw new AssertionError("Invalid state: " + state); - } - } - if (closing) { - if (!closed) { - closed = true; - accumulate.clear(); - accumulate.release(); - listener.close(); - } - } - } finally { - inDelivery = false; - } - } - - private boolean hasEnoughBytes() { - return requiredLength - accumulate.readableBytes() <= 0; - } - - /** - * Processes the GRPC compression header which is composed of the compression flag and the outer - * frame length. - */ - private void processHeader() { - int type = accumulate.readUnsignedByte(); - if ((type & RESERVED_MASK) != 0) { - throw new RpcException("gRPC frame header malformed: reserved bits not zero"); - } - compressedFlag = (type & COMPRESSED_FLAG_MASK) != 0; - - requiredLength = accumulate.readInt(); - - // Continue reading the frame body. - state = GrpcDecodeState.PAYLOAD; - } - - /** - * Processes the GRPC message body, which depending on frame header flags may be compressed. - */ - private void processBody() { - // There is no reliable way to get the uncompressed size per message when it's compressed, - // because the uncompressed bytes are provided through an InputStream whose total size is - // unknown until all bytes are read, and we don't know when it happens. - byte[] stream = compressedFlag ? getCompressedBody() : getUncompressedBody(); - - listener.onRawMessage(stream); - - // Done with this frame, begin processing the next header. - state = GrpcDecodeState.HEADER; - requiredLength = HEADER_LENGTH; - } - - private byte[] getCompressedBody() { - final byte[] compressedBody = getUncompressedBody(); - return decompressor.decompress(compressedBody); - } - - private byte[] getUncompressedBody() { - byte[] data = new byte[requiredLength]; - accumulate.readBytes(data); - accumulate.discardReadComponents(); - return data; - } - - private enum GrpcDecodeState { - HEADER, - PAYLOAD - } - - public interface Listener { - - void onRawMessage(byte[] data); - - void close(); - } -} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerHttpChannelObserver.java similarity index 78% rename from dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerHttpChannelObserver.java index c2473c85abbb..e4abd399d5d9 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerHttpChannelObserver.java @@ -14,12 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.remoting.http12; +package org.apache.dubbo.rpc.protocol.tri.h12; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.remoting.http12.ErrorResponse; +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.HttpMetadata; +import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.HttpUtils; +import org.apache.dubbo.remoting.http12.ServerHttpChannelObserver; import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import org.apache.dubbo.remoting.http12.message.ResponseEncoder; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.MessageHandlerRegistry; +import org.apache.dubbo.rpc.protocol.tri.OutputMessageHandler; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -30,19 +44,22 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR; import static org.apache.dubbo.common.logger.LoggerFactory.getErrorTypeAwareLogger; -public abstract class AbstractServerHttpChannelObserver implements ServerHttpChannelObserver { +public abstract class AbstractServerHttpChannelObserver, OUTPUT> + implements ServerHttpChannelObserver { private static final ErrorTypeAwareLogger LOGGER = getErrorTypeAwareLogger(AbstractServerHttpChannelObserver.class); private final H httpChannel; + private final OutputMessageHandler messageHandler; + private List> headersCustomizers; private List> trailersCustomizers; private Function exceptionCustomizer; - private HttpMessageEncoder responseEncoder; + private ResponseEncoder responseEncoder; private boolean headerSent; @@ -50,8 +67,11 @@ public abstract class AbstractServerHttpChannelObserver i private boolean closed; - protected AbstractServerHttpChannelObserver(H httpChannel) { + protected AbstractServerHttpChannelObserver( + FrameworkModel frameworkModel, H httpChannel, Class outputType) { this.httpChannel = httpChannel; + this.messageHandler = + findOutputMessageHandler(frameworkModel.getOrRegisterBean(MessageHandlerRegistry.class), outputType); } @Override @@ -80,12 +100,16 @@ public void setExceptionCustomizer(Function exceptionCustomizer) { this.exceptionCustomizer = exceptionCustomizer; } - public HttpMessageEncoder getResponseEncoder() { + public ResponseEncoder getResponseEncoder() { return responseEncoder; } public void setResponseEncoder(HttpMessageEncoder responseEncoder) { - this.responseEncoder = responseEncoder; + this.responseEncoder = createResponseEncoder(responseEncoder); + } + + protected final ResponseEncoder createResponseEncoder(HttpMessageEncoder responseEncoder) { + return messageHandler.createResponseEncoder(responseEncoder); } @Override @@ -143,7 +167,8 @@ public final void onCompleted() { protected void doOnNext(Object data) throws Throwable { int statusCode = resolveStatusCode(data); if (!headerSent) { - sendMetadata(buildMetadata(statusCode, data, null, HttpOutputMessage.EMPTY_MESSAGE)); + sendMetadata( + buildMetadata(statusCode, data, null, getMessageHandler().empty())); } sendMessage(buildMessage(statusCode, data)); } @@ -159,7 +184,7 @@ protected final int resolveStatusCode(Object data) { } protected final HttpMetadata buildMetadata( - int statusCode, Object data, Throwable throwable, HttpOutputMessage message) { + int statusCode, Object data, Throwable throwable, HttpOutputMessage message) { HttpMetadata metadata = encodeHttpMetadata(message == null); HttpHeaders headers = metadata.headers(); headers.set(HttpHeaderNames.STATUS.getKey(), HttpUtils.toStatusString(statusCode)); @@ -178,7 +203,7 @@ protected final HttpMetadata buildMetadata( protected abstract HttpMetadata encodeHttpMetadata(boolean endStream); - protected void customizeHeaders(HttpHeaders headers, Throwable throwable, HttpOutputMessage message) { + protected void customizeHeaders(HttpHeaders headers, Throwable throwable, HttpOutputMessage message) { List> headersCustomizers = this.headersCustomizers; if (headersCustomizers != null) { for (int i = 0, size = headersCustomizers.size(); i < size; i++) { @@ -198,7 +223,7 @@ protected final void sendMetadata(HttpMetadata metadata) { } } - protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Throwable { + protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Throwable { if (statusCode < 200 || statusCode == 204 || statusCode == 304) { return null; } @@ -221,7 +246,7 @@ protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Thr } catch (Throwable ignored) { } } - HttpOutputMessage message = encodeHttpOutputMessage(data); + HttpOutputMessage message = encodeHttpOutputMessage(data); try { preOutputMessage(message); responseEncoder.encode(message.getBody(), data); @@ -232,11 +257,11 @@ protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Thr return message; } - protected HttpOutputMessage encodeHttpOutputMessage(Object data) { + protected HttpOutputMessage encodeHttpOutputMessage(Object data) { return getHttpChannel().newOutputMessage(); } - protected final void sendMessage(HttpOutputMessage message) throws Throwable { + protected final void sendMessage(HttpOutputMessage message) throws Throwable { if (message == null) { return; } @@ -244,9 +269,9 @@ protected final void sendMessage(HttpOutputMessage message) throws Throwable { postOutputMessage(message); } - protected void preOutputMessage(HttpOutputMessage message) throws Throwable {} + protected void preOutputMessage(HttpOutputMessage message) throws Throwable {} - protected void postOutputMessage(HttpOutputMessage message) throws Throwable {} + protected void postOutputMessage(HttpOutputMessage message) throws Throwable {} protected Throwable customizeError(Throwable throwable) { if (exceptionCustomizer == null) { @@ -267,7 +292,8 @@ protected void doOnError(Throwable throwable) throws Throwable { int statusCode = resolveErrorStatusCode(throwable); Object data = buildErrorResponse(statusCode, throwable); if (!headerSent) { - sendMetadata(buildMetadata(statusCode, data, throwable, HttpOutputMessage.EMPTY_MESSAGE)); + sendMetadata(buildMetadata( + statusCode, data, throwable, getMessageHandler().empty())); } sendMessage(buildMessage(statusCode, data)); } @@ -351,4 +377,17 @@ public void close() { protected final void closed() { closed = true; } + + public final OutputMessageHandler getMessageHandler() { + return messageHandler; + } + + private OutputMessageHandler findOutputMessageHandler( + MessageHandlerRegistry registry, Class outputType) { + OutputMessageHandler handler = registry.get(outputType); + if (handler == null) { + throw new IllegalArgumentException("Unsupported message type: " + outputType); + } + return handler; + } } 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 28dc4dce3184..80424f331b73 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 @@ -28,6 +28,7 @@ import org.apache.dubbo.remoting.http12.HttpInputMessage; import org.apache.dubbo.remoting.http12.HttpStatus; import org.apache.dubbo.remoting.http12.HttpTransportListener; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.RequestMetadata; import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.remoting.http12.message.MethodMetadata; @@ -38,6 +39,8 @@ import org.apache.dubbo.rpc.model.MethodDescriptor; import org.apache.dubbo.rpc.protocol.tri.DescriptorUtils; import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; +import org.apache.dubbo.rpc.protocol.tri.InputMessageHandler; +import org.apache.dubbo.rpc.protocol.tri.MessageHandlerRegistry; import org.apache.dubbo.rpc.protocol.tri.RpcInvocationBuildContext; import org.apache.dubbo.rpc.protocol.tri.TripleConstants; import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum; @@ -51,29 +54,39 @@ import java.util.function.Function; import java.util.function.Supplier; -public abstract class AbstractServerTransportListener

- implements HttpTransportListener { +public abstract class AbstractServerTransportListener< + HEADER extends RequestMetadata, MESSAGE extends HttpInputMessage, INPUT, OUTPUT> + implements HttpTransportListener { private static final FluentLogger LOGGER = FluentLogger.of(AbstractServerTransportListener.class); private static final String HEADER_FILTERS_CACHE = "HEADER_FILTERS_CACHE"; private final FrameworkModel frameworkModel; private final URL url; - private final HttpChannel httpChannel; + private final HttpChannel httpChannel; private final RequestRouter requestRouter; private final ExceptionCustomizerWrapper exceptionCustomizerWrapper; + private final InputMessageHandler messageHandler; + private final MessageTypeToken typeToken; private Executor executor; private HEADER httpMetadata; private RpcInvocationBuildContext context; - private HttpMessageListener httpMessageListener; + private HttpMessageListener httpMessageListener; - protected AbstractServerTransportListener(FrameworkModel frameworkModel, URL url, HttpChannel httpChannel) { + protected AbstractServerTransportListener( + FrameworkModel frameworkModel, + URL url, + HttpChannel httpChannel, + MessageTypeToken typeToken) { this.frameworkModel = frameworkModel; this.url = url; this.httpChannel = httpChannel; - requestRouter = frameworkModel.getOrRegisterBean(DefaultRequestRouter.class); - exceptionCustomizerWrapper = new ExceptionCustomizerWrapper(frameworkModel); + this.typeToken = typeToken; + this.requestRouter = frameworkModel.getOrRegisterBean(DefaultRequestRouter.class); + this.exceptionCustomizerWrapper = new ExceptionCustomizerWrapper(frameworkModel); + this.messageHandler = + findMessageHandler(frameworkModel.getOrRegisterBean(MessageHandlerRegistry.class), typeToken); } @Override @@ -141,7 +154,7 @@ protected void onPrepareMetadata(HEADER metadata) { // default no op } - protected abstract HttpMessageListener buildHttpMessageListener(); + protected abstract HttpMessageListener buildHttpMessageListener(); protected void onMetadataCompletion(HEADER metadata) { // default no op @@ -333,7 +346,7 @@ public final RpcInvocationBuildContext getContext() { return context; } - protected final void setHttpMessageListener(HttpMessageListener httpMessageListener) { + protected final void setHttpMessageListener(HttpMessageListener httpMessageListener) { this.httpMessageListener = httpMessageListener; } @@ -345,4 +358,24 @@ protected void setMethodDescriptor(MethodDescriptor methodDescriptor) { context.setMethodDescriptor(methodDescriptor); exceptionCustomizerWrapper.setMethodDescriptor(methodDescriptor); } + + protected final InputMessageHandler getMessageHandler() { + return messageHandler; + } + + protected final MessageTypeToken getTypeToken() { + return typeToken; + } + + @SuppressWarnings("unchecked") + private InputMessageHandler findMessageHandler( + MessageHandlerRegistry registry, MessageTypeToken typeToken) { + InputMessageHandler handler = registry.get(typeToken.getInputType(), protocol()); + if (handler == null) { + throw new IllegalArgumentException("Unsupported message type: " + typeToken.getInputType()); + } + return handler; + } + + protected abstract String protocol(); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/DefaultHttpMessageListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/DefaultHttpMessageListener.java index d0e6cdb877fd..df3050c4fb44 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/DefaultHttpMessageListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/DefaultHttpMessageListener.java @@ -18,24 +18,22 @@ import org.apache.dubbo.remoting.http12.message.ListeningDecoder; -import java.io.InputStream; +public class DefaultHttpMessageListener implements HttpMessageListener { -public class DefaultHttpMessageListener implements HttpMessageListener { - - private ListeningDecoder listeningDecoder; + private ListeningDecoder listeningDecoder; public DefaultHttpMessageListener() {} - public DefaultHttpMessageListener(ListeningDecoder listeningDecoder) { + public DefaultHttpMessageListener(ListeningDecoder listeningDecoder) { this.listeningDecoder = listeningDecoder; } - public void setListeningDecoder(ListeningDecoder listeningDecoder) { + public void setListeningDecoder(ListeningDecoder listeningDecoder) { this.listeningDecoder = listeningDecoder; } @Override - public void onMessage(InputStream inputStream) { - listeningDecoder.decode(inputStream); + public void onMessage(T input) { + listeningDecoder.decode(input); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpMessageListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpMessageListener.java index 810af9bdedd0..3ae812eca001 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpMessageListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpMessageListener.java @@ -16,9 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.h12; -import java.io.InputStream; +public interface HttpMessageListener { -public interface HttpMessageListener { - - void onMessage(InputStream inputStream); + void onMessage(T input); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcByteBufInputMessageHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcByteBufInputMessageHandler.java new file mode 100644 index 000000000000..26d5a3c6e64a --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcByteBufInputMessageHandler.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.h12.grpc; + +import org.apache.dubbo.remoting.http12.message.StreamingDecoder; +import org.apache.dubbo.rpc.protocol.tri.ByteBufInputMessageHandler; + +import io.netty.buffer.ByteBuf; + +public class GrpcByteBufInputMessageHandler extends ByteBufInputMessageHandler { + + @Override + public StreamingDecoder createStreamingDecoder() { + return new GrpcByteBufStreamingDecoder(); + } + + @Override + public String supportProtocol() { + return "grpc"; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcByteBufStreamingDecoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcByteBufStreamingDecoder.java new file mode 100644 index 000000000000..b48e88190e82 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcByteBufStreamingDecoder.java @@ -0,0 +1,77 @@ +/* + * 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.remoting.http12.message.ByteBufLengthFieldDecoder; +import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.protocol.tri.compressor.CompressorConfigure; +import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor; + +import io.netty.buffer.ByteBuf; + +public class GrpcByteBufStreamingDecoder extends ByteBufLengthFieldDecoder implements CompressorConfigure { + + private static final int COMPRESSED_FLAG_MASK = 1; + private static final int RESERVED_MASK = 0xFE; + + private boolean compressedFlag; + + private DeCompressor deCompressor = DeCompressor.NONE; + + public GrpcByteBufStreamingDecoder() { + super(1, 4); + } + + @Override + public void setDeCompressor(DeCompressor deCompressor) { + this.deCompressor = deCompressor; + } + + @Override + protected void processHeader() { + ByteBuf offsetBuffer = accumulate.readSlice(lengthFieldOffset); + processOffset(offsetBuffer); + requiredLength = readLengthField(accumulate, lengthFieldLength); + state = DecodeState.PAYLOAD; + } + + @Override + protected void processBody() { + ByteBuf rawMessage = readRawMessage(accumulate, requiredLength); + invokeListener(rawMessage); + state = DecodeState.HEADER; + requiredLength = fixedHeaderLength; + accumulate.discardReadComponents(); + } + + protected void processOffset(ByteBuf buffer) { + byte type = buffer.readByte(); + if ((type & RESERVED_MASK) != 0) { + throw new RpcException("gRPC frame header malformed: reserved bits not zero"); + } + compressedFlag = (type & COMPRESSED_FLAG_MASK) != 0; + } + + protected ByteBuf readRawMessage(ByteBuf buffer, int length) { + ByteBuf rawMessage = buffer.readSlice(length); + return compressedFlag ? deCompressedMessage(rawMessage) : rawMessage; + } + + private ByteBuf deCompressedMessage(ByteBuf rawMessage) { + return deCompressor.decompress(rawMessage); + } +} 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 e66eebad7901..829e7166190a 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 @@ -31,6 +31,7 @@ import org.apache.dubbo.rpc.model.MethodDescriptor; import org.apache.dubbo.rpc.model.PackableMethod; import org.apache.dubbo.rpc.model.PackableMethodFactory; +import org.apache.dubbo.rpc.protocol.tri.ByteBufPackableMethod; import java.io.IOException; import java.io.InputStream; @@ -38,6 +39,10 @@ import java.nio.charset.Charset; import java.util.concurrent.ConcurrentHashMap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; + import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PACKABLE_METHOD_FACTORY; @@ -94,6 +99,26 @@ public void encode(OutputStream outputStream, Object data, Charset charset) thro } } + @Override + public void encode(ByteBuf buffer, Object data, Charset charset) throws EncodeException { + try { + if (!(packableMethod instanceof ByteBufPackableMethod)) { + encode(new ByteBufOutputStream(buffer), data, charset); + return; + } + buffer.writeByte(0); + int position = buffer.writerIndex(); + buffer.writerIndex(position + 4); + ((ByteBufPackableMethod) packableMethod).packResponse(buffer, data); + int length = buffer.writerIndex() - position - 4; + buffer.setInt(position, length); + } catch (HttpStatusException e) { + throw e; + } catch (Exception e) { + throw new EncodeException(e); + } + } + @Override public Object decode(InputStream inputStream, Class targetType, Charset charset) throws DecodeException { try { @@ -115,6 +140,29 @@ public Object[] decode(InputStream inputStream, Class[] targetTypes, Charset return new Object[] {message}; } + @Override + public Object decode(ByteBuf buffer, Class targetTypes, Charset charset) throws DecodeException { + try { + if (!(packableMethod instanceof ByteBufPackableMethod)) { + return decode(new ByteBufInputStream(buffer), targetTypes, charset); + } + return ((ByteBufPackableMethod) packableMethod).parseRequest(buffer); + } catch (HttpStatusException e) { + throw e; + } catch (Exception e) { + throw new DecodeException(e); + } + } + + @Override + public Object[] decode(ByteBuf buffer, Class[] targetTypes, Charset charset) throws DecodeException { + Object message = decode(buffer, ArrayUtils.isEmpty(targetTypes) ? null : targetTypes[0], charset); + if (message instanceof Object[]) { + return (Object[]) message; + } + return new Object[] {message}; + } + private void writeLength(OutputStream outputStream, int length) { try { outputStream.write(((length >> 24) & 0xFF)); 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 8f6c3350d3d5..26c16121919c 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 @@ -20,40 +20,45 @@ 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.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.exception.DecodeException; import org.apache.dubbo.remoting.http12.exception.UnimplementedException; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2Header; -import org.apache.dubbo.remoting.http12.h2.Http2ServerChannelObserver; import org.apache.dubbo.remoting.http12.h2.Http2TransportListener; +import org.apache.dubbo.remoting.http12.message.AbstractLengthFieldStreamingDecoder; import org.apache.dubbo.remoting.http12.message.MethodMetadata; import org.apache.dubbo.remoting.http12.message.StreamingDecoder; import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.MethodDescriptor; -import org.apache.dubbo.rpc.protocol.tri.DescriptorUtils; import org.apache.dubbo.rpc.protocol.tri.ReflectionPackableMethod; import org.apache.dubbo.rpc.protocol.tri.RpcInvocationBuildContext; +import org.apache.dubbo.rpc.protocol.tri.compressor.CompressorConfigure; 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.h12.http2.Http2ServerChannelObserver; import java.io.IOException; -import java.io.InputStream; import java.util.concurrent.Executor; import java.util.function.Function; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_PARSE; -public class GrpcHttp2ServerTransportListener extends GenericHttp2ServerTransportListener - implements Http2TransportListener { +public class GrpcHttp2ServerTransportListener extends GenericHttp2ServerTransportListener + implements Http2TransportListener { private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(GrpcHttp2ServerTransportListener.class); - public GrpcHttp2ServerTransportListener(H2StreamChannel h2StreamChannel, URL url, FrameworkModel frameworkModel) { - super(h2StreamChannel, url, frameworkModel); + protected GrpcHttp2ServerTransportListener( + H2StreamChannel h2StreamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + super(h2StreamChannel, url, frameworkModel, typeToken); } @Override @@ -83,33 +88,30 @@ private void processGrpcHeaders(Http2Header metadata) { throw new UnimplementedException( GrpcHeaderNames.GRPC_ENCODING.getName() + " '" + messageEncoding + "'"); } - ((GrpcStreamingDecoder) getStreamingDecoder()).setDeCompressor(compressor); + ((CompressorConfigure) getStreamingDecoder()).setDeCompressor(compressor); } } @Override - protected StreamingDecoder newStreamingDecoder() { - return new GrpcStreamingDecoder(); + protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { + return new GrpcUnaryServerChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); } @Override - protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { - return new GrpcUnaryServerChannelObserver(getFrameworkModel(), h2StreamChannel); + protected Http2ServerChannelObserver newStreamResponseObserver( + H2StreamChannel h2StreamChannel) { + return new GrpcStreamServerChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); } @Override - protected Http2ServerChannelObserver newStreamResponseObserver(H2StreamChannel h2StreamChannel) { - return new GrpcStreamServerChannelObserver(getFrameworkModel(), h2StreamChannel); - } - - @Override - protected Http2ServerChannelObserver prepareResponseObserver(Http2ServerChannelObserver responseObserver) { + protected Http2ServerChannelObserver prepareResponseObserver( + Http2ServerChannelObserver responseObserver) { responseObserver.addTrailersCustomizer(getExceptionCustomizerWrapper()::customizeGrpcStatus); return super.prepareResponseObserver(responseObserver); } @Override - protected HttpMessageListener buildHttpMessageListener() { + protected HttpMessageListener buildHttpMessageListener() { return getContext().isHasStub() ? super.buildHttpMessageListener() : new LazyFindMethodListener(); } @@ -165,44 +167,55 @@ protected void setMethodDescriptor(MethodDescriptor methodDescriptor) { super.setMethodDescriptor(methodDescriptor); } - private class LazyFindMethodListener implements HttpMessageListener { + @Override + protected String protocol() { + return "grpc"; + } + + private class LazyFindMethodListener implements HttpMessageListener { - private final StreamingDecoder streamingDecoder; + private final StreamingDecoder streamingDecoder; private LazyFindMethodListener() { - streamingDecoder = new GrpcStreamingDecoder(); + streamingDecoder = newStreamingDecoder(); streamingDecoder.setFragmentListener(new DetermineMethodDescriptorListener()); streamingDecoder.request(Integer.MAX_VALUE); } @Override - public void onMessage(InputStream inputStream) { + public void onMessage(INPUT inputStream) { streamingDecoder.decode(inputStream); } } - private class DetermineMethodDescriptorListener implements StreamingDecoder.FragmentListener { + private class DetermineMethodDescriptorListener implements StreamingDecoder.FragmentListener { @Override public void onClose() { getStreamingDecoder().close(); } + @SuppressWarnings({"unchecked", "rawtypes"}) @Override - public void onFragmentMessage(InputStream rawMessage) { + public void onFragmentMessage(INPUT rawMessage) { try { RpcInvocationBuildContext context = getContext(); if (context.getMethodDescriptor() == null) { - MethodDescriptor methodDescriptor = DescriptorUtils.findTripleMethodDescriptor( - context.getServiceDescriptor(), context.getMethodName(), rawMessage); + MethodDescriptor methodDescriptor = findMethodDescriptor(context, rawMessage); setMethodDescriptor(methodDescriptor); setHttpMessageListener(GrpcHttp2ServerTransportListener.super.buildHttpMessageListener()); } - ((GrpcStreamingDecoder) getStreamingDecoder()).invokeListener(rawMessage); + ((AbstractLengthFieldStreamingDecoder) getStreamingDecoder()).invokeListener(rawMessage); } catch (IOException e) { throw new DecodeException(e); } } } + + protected MethodDescriptor findMethodDescriptor(RpcInvocationBuildContext context, INPUT rawMessage) + throws IOException { + return getMessageHandler() + .findMethodDescriptor(context.getServiceDescriptor(), context.getMethodName(), rawMessage); + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListenerFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListenerFactory.java index c488204e90c4..342f1383c331 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListenerFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListenerFactory.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.h12.grpc; import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2ServerTransportListenerFactory; import org.apache.dubbo.remoting.http12.h2.Http2TransportListener; @@ -25,8 +26,12 @@ public class GrpcHttp2ServerTransportListenerFactory implements Http2ServerTransportListenerFactory { @Override - public Http2TransportListener newInstance(H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel) { - return new GrpcHttp2ServerTransportListener(streamChannel, url, frameworkModel); + public Http2TransportListener newInstance( + H2StreamChannel streamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + return new GrpcHttp2ServerTransportListener<>(streamChannel, url, frameworkModel, typeToken); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcInputStreamMessageHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcInputStreamMessageHandler.java new file mode 100644 index 000000000000..c8b1dda56bd5 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcInputStreamMessageHandler.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.h12.grpc; + +import org.apache.dubbo.remoting.http12.message.StreamingDecoder; +import org.apache.dubbo.rpc.protocol.tri.InputStreamMessageHandler; + +import java.io.InputStream; + +public class GrpcInputStreamMessageHandler extends InputStreamMessageHandler { + + @Override + public StreamingDecoder createStreamingDecoder() { + return new GrpcStreamingDecoder(); + } + + @Override + public String supportProtocol() { + return "grpc"; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcStreamServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcStreamServerChannelObserver.java index 27825d2fbe97..5f567d0821c5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcStreamServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcStreamServerChannelObserver.java @@ -16,15 +16,19 @@ */ package org.apache.dubbo.rpc.protocol.tri.h12.grpc; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.h12.http2.Http2StreamServerChannelObserver; -public class GrpcStreamServerChannelObserver extends Http2StreamServerChannelObserver { +public class GrpcStreamServerChannelObserver extends Http2StreamServerChannelObserver { - public GrpcStreamServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(frameworkModel, h2StreamChannel); + public GrpcStreamServerChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcStreamingDecoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcStreamingDecoder.java index d0bc805afcb9..7b7c9f15c125 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcStreamingDecoder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcStreamingDecoder.java @@ -16,14 +16,16 @@ */ package org.apache.dubbo.rpc.protocol.tri.h12.grpc; -import org.apache.dubbo.remoting.http12.message.LengthFieldStreamingDecoder; +import org.apache.dubbo.remoting.http12.message.InputStreamLengthFieldDecoder; import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.protocol.tri.compressor.CompressorConfigure; import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -public class GrpcStreamingDecoder extends LengthFieldStreamingDecoder { +public class GrpcStreamingDecoder extends InputStreamLengthFieldDecoder implements CompressorConfigure { private static final int COMPRESSED_FLAG_MASK = 1; private static final int RESERVED_MASK = 0xFE; @@ -36,12 +38,29 @@ public GrpcStreamingDecoder() { super(1, 4); } + @Override public void setDeCompressor(DeCompressor deCompressor) { this.deCompressor = deCompressor; } @Override - protected void processOffset(InputStream inputStream, int lengthFieldOffset) throws IOException { + protected void processHeader() throws IOException { + byte[] offsetData = new byte[lengthFieldOffset]; + accumulate.read(offsetData); + processOffset(new ByteArrayInputStream(offsetData)); + requiredLength = readLengthField(accumulate, lengthFieldLength); + state = DecodeState.PAYLOAD; + } + + @Override + protected void processBody() throws IOException { + byte[] rawMessage = readRawMessage(accumulate, requiredLength); + invokeListener(new ByteArrayInputStream(rawMessage)); + state = DecodeState.HEADER; + requiredLength = fixedHeaderLength; + } + + protected void processOffset(InputStream inputStream) throws IOException { int type = inputStream.read(); if ((type & RESERVED_MASK) != 0) { throw new RpcException("gRPC frame header malformed: reserved bits not zero"); @@ -49,9 +68,9 @@ protected void processOffset(InputStream inputStream, int lengthFieldOffset) thr compressedFlag = (type & COMPRESSED_FLAG_MASK) != 0; } - @Override protected byte[] readRawMessage(InputStream inputStream, int length) throws IOException { - byte[] rawMessage = super.readRawMessage(inputStream, length); + byte[] rawMessage = new byte[length]; + inputStream.read(rawMessage); return compressedFlag ? deCompressedMessage(rawMessage) : rawMessage; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcUnaryServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcUnaryServerChannelObserver.java index 285401a57a2e..2c84825bbf24 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcUnaryServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcUnaryServerChannelObserver.java @@ -16,13 +16,17 @@ */ package org.apache.dubbo.rpc.protocol.tri.h12.grpc; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.rpc.model.FrameworkModel; -public class GrpcUnaryServerChannelObserver extends GrpcStreamServerChannelObserver { +public class GrpcUnaryServerChannelObserver extends GrpcStreamServerChannelObserver { - public GrpcUnaryServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(frameworkModel, h2StreamChannel); + public GrpcUnaryServerChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); } @Override 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 8aae457476b7..9758033b892e 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 @@ -22,10 +22,10 @@ import org.apache.dubbo.remoting.http12.HttpChannel; import org.apache.dubbo.remoting.http12.HttpHeaderNames; import org.apache.dubbo.remoting.http12.HttpInputMessage; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.RequestMetadata; -import org.apache.dubbo.remoting.http12.h1.Http1ServerChannelObserver; import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener; -import org.apache.dubbo.remoting.http12.message.DefaultListeningDecoder; +import org.apache.dubbo.remoting.http12.message.ListeningDecoder; import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.remoting.http12.message.codec.JsonCodec; import org.apache.dubbo.rpc.Invoker; @@ -41,20 +41,26 @@ import org.apache.dubbo.rpc.protocol.tri.h12.ServerStreamServerCallListener; import org.apache.dubbo.rpc.protocol.tri.h12.UnaryServerCallListener; -public class DefaultHttp11ServerTransportListener - extends AbstractServerTransportListener - implements Http1ServerTransportListener { +public class DefaultHttp11ServerTransportListener + extends AbstractServerTransportListener, INPUT, OUTPUT> + implements Http1ServerTransportListener { - private final HttpChannel httpChannel; - private Http1ServerChannelObserver responseObserver; + private final HttpChannel httpChannel; + private Http1ServerChannelObserver responseObserver; - public DefaultHttp11ServerTransportListener(HttpChannel httpChannel, URL url, FrameworkModel frameworkModel) { - super(frameworkModel, url, httpChannel); + public DefaultHttp11ServerTransportListener( + HttpChannel httpChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + super(frameworkModel, url, httpChannel, typeToken); this.httpChannel = httpChannel; - responseObserver = prepareResponseObserver(new Http1UnaryServerChannelObserver(httpChannel)); + responseObserver = prepareResponseObserver(new Http1UnaryServerChannelObserver<>( + frameworkModel, httpChannel, getTypeToken().getOutputType())); } - private Http1ServerChannelObserver prepareResponseObserver(Http1ServerChannelObserver responseObserver) { + private Http1ServerChannelObserver prepareResponseObserver( + Http1ServerChannelObserver responseObserver) { responseObserver.setExceptionCustomizer(getExceptionCustomizer()); RpcInvocationBuildContext context = getContext(); responseObserver.setResponseEncoder(context == null ? JsonCodec.INSTANCE : context.getHttpMessageEncoder()); @@ -62,16 +68,18 @@ private Http1ServerChannelObserver prepareResponseObserver(Http1ServerChannelObs } @Override - protected HttpMessageListener buildHttpMessageListener() { + 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 listeningDecoder = getMessageHandler() + .createListeningDecoder( + context.getHttpMessageDecoder(), + context.getMethodMetadata().getActualRequestTypes()); listeningDecoder.setListener(serverCallListener::onMessage); - return new DefaultHttpMessageListener(listeningDecoder); + return new DefaultHttpMessageListener<>(listeningDecoder); } private ServerCallListener startListener( @@ -80,7 +88,8 @@ private ServerCallListener startListener( case UNARY: return new AutoCompleteUnaryServerCallListener(invocation, invoker, responseObserver); case SERVER_STREAM: - responseObserver = prepareResponseObserver(new Http1SseServerChannelObserver(httpChannel)); + responseObserver = prepareResponseObserver(new Http1SseServerChannelObserver<>( + getFrameworkModel(), httpChannel, getTypeToken().getOutputType())); responseObserver.addHeadersCustomizer((hs, t) -> hs.set(HttpHeaderNames.CONTENT_TYPE.getKey(), MediaType.TEXT_EVENT_STREAM.getName())); return new AutoCompleteServerStreamServerCallListener(invocation, invoker, responseObserver); @@ -99,6 +108,11 @@ protected void onError(Throwable throwable) { responseObserver.onError(throwable); } + @Override + protected String protocol() { + return "http"; + } + @Override protected void initializeAltSvc(URL url) { String protocolId = Http3Exchanger.isEnabled(url) ? "h3" : "h2"; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListenerFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListenerFactory.java index 042a7af719a6..6d418c35395a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListenerFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListenerFactory.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.remoting.http12.HttpChannel; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener; import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListenerFactory; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -28,7 +29,11 @@ public class DefaultHttp11ServerTransportListenerFactory implements Http1ServerT new DefaultHttp11ServerTransportListenerFactory(); @Override - public Http1ServerTransportListener newInstance(HttpChannel httpChannel, URL url, FrameworkModel frameworkModel) { - return new DefaultHttp11ServerTransportListener(httpChannel, url, frameworkModel); + public Http1ServerTransportListener newInstance( + HttpChannel httpChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + return new DefaultHttp11ServerTransportListener<>(httpChannel, url, frameworkModel, typeToken); } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1ServerChannelObserver.java similarity index 66% rename from dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerChannelObserver.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1ServerChannelObserver.java index a2ff71cc0074..d92d39bf8954 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1ServerChannelObserver.java @@ -14,18 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.remoting.http12.h1; +package org.apache.dubbo.rpc.protocol.tri.h12.http1; -import org.apache.dubbo.remoting.http12.AbstractServerHttpChannelObserver; import org.apache.dubbo.remoting.http12.HttpChannel; import org.apache.dubbo.remoting.http12.HttpMetadata; -import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.h1.Http1Metadata; import org.apache.dubbo.remoting.http12.netty4.h1.NettyHttp1HttpHeaders; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.h12.AbstractServerHttpChannelObserver; -public class Http1ServerChannelObserver extends AbstractServerHttpChannelObserver { +public class Http1ServerChannelObserver extends AbstractServerHttpChannelObserver, OUTPUT> { - public Http1ServerChannelObserver(HttpChannel httpChannel) { - super(httpChannel); + public Http1ServerChannelObserver( + FrameworkModel frameworkModel, HttpChannel httpChannel, Class outputType) { + super(frameworkModel, httpChannel, outputType); } @Override @@ -35,6 +37,6 @@ protected HttpMetadata encodeHttpMetadata(boolean endStream) { @Override protected void doOnCompleted(Throwable throwable) { - getHttpChannel().writeMessage(HttpOutputMessage.EMPTY_MESSAGE); + getHttpChannel().writeMessage(getMessageHandler().empty()); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1SseServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1SseServerChannelObserver.java index 7499a16c95c8..27d08c5cda2c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1SseServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1SseServerChannelObserver.java @@ -22,22 +22,24 @@ import org.apache.dubbo.remoting.http12.HttpMetadata; import org.apache.dubbo.remoting.http12.HttpOutputMessage; import org.apache.dubbo.remoting.http12.HttpResult; -import org.apache.dubbo.remoting.http12.h1.Http1ServerChannelObserver; import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import org.apache.dubbo.remoting.http12.message.ResponseEncoder; import org.apache.dubbo.remoting.http12.message.ServerSentEventEncoder; +import org.apache.dubbo.rpc.model.FrameworkModel; -public class Http1SseServerChannelObserver extends Http1ServerChannelObserver { +public class Http1SseServerChannelObserver extends Http1ServerChannelObserver { - private HttpMessageEncoder originalResponseEncoder; + private ResponseEncoder originalResponseEncoder; - public Http1SseServerChannelObserver(HttpChannel httpChannel) { - super(httpChannel); + public Http1SseServerChannelObserver( + FrameworkModel frameworkModel, HttpChannel httpChannel, Class outputType) { + super(frameworkModel, httpChannel, outputType); } @Override public void setResponseEncoder(HttpMessageEncoder responseEncoder) { super.setResponseEncoder(new ServerSentEventEncoder(responseEncoder)); - this.originalResponseEncoder = responseEncoder; + this.originalResponseEncoder = super.createResponseEncoder(responseEncoder); } @Override @@ -56,7 +58,7 @@ protected HttpMetadata encodeHttpMetadata(boolean endStream) { } @Override - protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Throwable { + protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Throwable { if (data instanceof HttpResult) { data = ((HttpResult) data).getBody(); @@ -64,7 +66,7 @@ protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Thr return null; } - HttpOutputMessage message = encodeHttpOutputMessage(data); + HttpOutputMessage message = encodeHttpOutputMessage(data); try { originalResponseEncoder.encode(message.getBody(), data); } catch (Throwable t) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1UnaryServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1UnaryServerChannelObserver.java index 1aa994de5255..854dc2f25f26 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1UnaryServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1UnaryServerChannelObserver.java @@ -20,25 +20,26 @@ import org.apache.dubbo.remoting.http12.HttpHeaderNames; import org.apache.dubbo.remoting.http12.HttpHeaders; import org.apache.dubbo.remoting.http12.HttpOutputMessage; -import org.apache.dubbo.remoting.http12.h1.Http1ServerChannelObserver; +import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; import java.io.ByteArrayOutputStream; -import java.io.OutputStream; +import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufOutputStream; -public final class Http1UnaryServerChannelObserver extends Http1ServerChannelObserver { +public final class Http1UnaryServerChannelObserver extends Http1ServerChannelObserver { - public Http1UnaryServerChannelObserver(HttpChannel httpChannel) { - super(httpChannel); + public Http1UnaryServerChannelObserver( + FrameworkModel frameworkModel, HttpChannel httpChannel, Class outputType) { + super(frameworkModel, httpChannel, outputType); } @Override protected void doOnNext(Object data) throws Throwable { int statusCode = resolveStatusCode(data); - HttpOutputMessage message = buildMessage(statusCode, data); + HttpOutputMessage message = buildMessage(statusCode, data); sendMetadata(buildMetadata(statusCode, data, null, message)); sendMessage(message); } @@ -47,18 +48,20 @@ protected void doOnNext(Object data) throws Throwable { protected void doOnError(Throwable throwable) throws Throwable { int statusCode = resolveErrorStatusCode(throwable); Object data = buildErrorResponse(statusCode, throwable); - HttpOutputMessage message = buildMessage(statusCode, data); + HttpOutputMessage message = buildMessage(statusCode, data); sendMetadata(buildMetadata(statusCode, data, throwable, message)); sendMessage(message); } @Override - protected void customizeHeaders(HttpHeaders headers, Throwable throwable, HttpOutputMessage message) { + protected void customizeHeaders(HttpHeaders headers, Throwable throwable, HttpOutputMessage message) { super.customizeHeaders(headers, throwable, message); int contentLength = 0; if (message != null) { - OutputStream body = message.getBody(); - if (body instanceof ByteBufOutputStream) { + OUTPUT body = message.getBody(); + if (body instanceof ByteBuf) { + contentLength = ((ByteBuf) body).readableBytes(); + } else if (body instanceof ByteBufOutputStream) { contentLength = ((ByteBufOutputStream) body).writtenBytes(); } else if (body instanceof ByteArrayOutputStream) { contentLength = ((ByteArrayOutputStream) body).size(); 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 f4f0aeefb3dd..6e63e059fbc6 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,14 +19,12 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.remoting.http12.HttpHeaderNames; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.CancelStreamException; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2Header; import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; -import org.apache.dubbo.remoting.http12.h2.Http2ServerChannelObserver; import org.apache.dubbo.remoting.http12.h2.Http2TransportListener; -import org.apache.dubbo.remoting.http12.message.DefaultListeningDecoder; -import org.apache.dubbo.remoting.http12.message.DefaultStreamingDecoder; import org.apache.dubbo.remoting.http12.message.ListeningDecoder; import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.remoting.http12.message.StreamingDecoder; @@ -45,41 +43,45 @@ import org.apache.dubbo.rpc.protocol.tri.h12.ServerStreamServerCallListener; import org.apache.dubbo.rpc.protocol.tri.h12.UnaryServerCallListener; -import java.io.InputStream; +public class GenericHttp2ServerTransportListener + extends AbstractServerTransportListener, INPUT, OUTPUT> + implements Http2TransportListener { -public class GenericHttp2ServerTransportListener extends AbstractServerTransportListener - implements Http2TransportListener { - - private final H2StreamChannel h2StreamChannel; - private final StreamingDecoder streamingDecoder; - private Http2ServerChannelObserver responseObserver; + private final H2StreamChannel h2StreamChannel; + private final StreamingDecoder streamingDecoder; + private Http2ServerChannelObserver responseObserver; private ServerCallListener serverCallListener; public GenericHttp2ServerTransportListener( - H2StreamChannel h2StreamChannel, URL url, FrameworkModel frameworkModel) { - super(frameworkModel, url, h2StreamChannel); + H2StreamChannel h2StreamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + super(frameworkModel, url, h2StreamChannel, typeToken); this.h2StreamChannel = h2StreamChannel; streamingDecoder = newStreamingDecoder(); responseObserver = prepareResponseObserver(newResponseObserver(h2StreamChannel)); } - protected StreamingDecoder newStreamingDecoder() { - return new DefaultStreamingDecoder(); + protected StreamingDecoder newStreamingDecoder() { + return getMessageHandler().createStreamingDecoder(); } - protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { - return new Http2UnaryServerChannelObserver(getFrameworkModel(), h2StreamChannel); + protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { + return new Http2UnaryServerChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); } - protected Http2ServerChannelObserver newStreamResponseObserver(H2StreamChannel h2StreamChannel) { - Http2ServerChannelObserver responseObserver = - new Http2SseServerChannelObserver(getFrameworkModel(), h2StreamChannel); + protected Http2ServerChannelObserver newStreamResponseObserver( + H2StreamChannel h2StreamChannel) { + Http2ServerChannelObserver responseObserver = + new Http2SseServerChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); responseObserver.addHeadersCustomizer( (hs, t) -> hs.set(HttpHeaderNames.CONTENT_TYPE.getKey(), MediaType.TEXT_EVENT_STREAM.getName())); return responseObserver; } - protected Http2ServerChannelObserver prepareResponseObserver(Http2ServerChannelObserver responseObserver) { + protected Http2ServerChannelObserver prepareResponseObserver( + Http2ServerChannelObserver responseObserver) { responseObserver.setExceptionCustomizer(getExceptionCustomizer()); RpcInvocationBuildContext context = getContext(); responseObserver.setResponseEncoder(context == null ? JsonCodec.INSTANCE : context.getHttpMessageEncoder()); @@ -89,16 +91,15 @@ protected Http2ServerChannelObserver prepareResponseObserver(Http2ServerChannelO } @Override - protected HttpMessageListener buildHttpMessageListener() { + 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 listeningDecoder = newListeningDecoder(context); listeningDecoder.setListener(new Http2StreamingDecodeListener(serverCallListener)); - streamingDecoder.setFragmentListener(new StreamingDecoder.DefaultFragmentListener(listeningDecoder)); - return new StreamingHttpMessageListener(streamingDecoder); + streamingDecoder.setFragmentListener(new StreamingDecoder.DefaultFragmentListener<>(listeningDecoder)); + return new StreamingHttpMessageListener<>(streamingDecoder); } private ServerCallListener startListener( @@ -125,6 +126,13 @@ protected void prepareStreamServerCall() { responseObserver = prepareResponseObserver(newStreamResponseObserver(h2StreamChannel)); } + protected ListeningDecoder newListeningDecoder(RpcInvocationBuildContext context) { + return getMessageHandler() + .createListeningDecoder( + context.getHttpMessageDecoder(), + context.getMethodMetadata().getActualRequestTypes()); + } + @Override protected void initializeAltSvc(URL url) { if (Http3Exchanger.isEnabled(url)) { @@ -143,7 +151,7 @@ protected void onMetadataCompletion(Http2Header metadata) { } @Override - protected void onDataCompletion(Http2InputMessage message) { + protected void onDataCompletion(Http2InputMessage message) { if (message.isEndStream()) { getStreamingDecoder().close(); } @@ -155,7 +163,12 @@ protected void onError(Throwable throwable) { } @Override - protected void onError(Http2InputMessage message, Throwable throwable) { + protected String protocol() { + return "http"; + } + + @Override + protected void onError(Http2InputMessage message, Throwable throwable) { try { message.close(); } catch (Exception e) { @@ -165,7 +178,7 @@ protected void onError(Http2InputMessage message, Throwable throwable) { } @Override - protected void onDataFinally(Http2InputMessage message) {} + protected void onDataFinally(Http2InputMessage message) {} @Override public void cancelByRemote(long errorCode) { @@ -175,11 +188,11 @@ public void cancelByRemote(long errorCode) { } } - protected final StreamingDecoder getStreamingDecoder() { + protected final StreamingDecoder getStreamingDecoder() { return streamingDecoder; } - protected final Http2ServerChannelObserver getResponseObserver() { + protected final Http2ServerChannelObserver getResponseObserver() { return responseObserver; } @@ -207,16 +220,16 @@ public void onClose() { } } - private static final class StreamingHttpMessageListener implements HttpMessageListener { + private static final class StreamingHttpMessageListener implements HttpMessageListener { - private final StreamingDecoder streamingDecoder; + private final StreamingDecoder streamingDecoder; - StreamingHttpMessageListener(StreamingDecoder streamingDecoder) { + StreamingHttpMessageListener(StreamingDecoder streamingDecoder) { this.streamingDecoder = streamingDecoder; } @Override - public void onMessage(InputStream inputStream) { + public void onMessage(INPUT inputStream) { streamingDecoder.decode(inputStream); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListenerFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListenerFactory.java index 5faa17595d64..de1448ca4eaa 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListenerFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListenerFactory.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.h12.http2; import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2ServerTransportListenerFactory; import org.apache.dubbo.remoting.http12.h2.Http2TransportListener; @@ -27,8 +28,12 @@ public class GenericHttp2ServerTransportListenerFactory implements Http2ServerTr public static final Http2ServerTransportListenerFactory INSTANCE = new GenericHttp2ServerTransportListenerFactory(); @Override - public Http2TransportListener newInstance(H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel) { - return new GenericHttp2ServerTransportListener(streamChannel, url, frameworkModel); + public Http2TransportListener newInstance( + H2StreamChannel streamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + return new GenericHttp2ServerTransportListener<>(streamChannel, url, frameworkModel, typeToken); } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerChannelObserver.java similarity index 76% rename from dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ServerChannelObserver.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerChannelObserver.java index f86ad12cfbdc..d81d90980af4 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerChannelObserver.java @@ -14,35 +14,45 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.remoting.http12.h2; +package org.apache.dubbo.rpc.protocol.tri.h12.http2; -import org.apache.dubbo.remoting.http12.AbstractServerHttpChannelObserver; import org.apache.dubbo.remoting.http12.ErrorCodeHolder; import org.apache.dubbo.remoting.http12.FlowControlStreamObserver; import org.apache.dubbo.remoting.http12.HttpConstants; 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.MessageTypeToken; +import org.apache.dubbo.remoting.http12.h2.CancelStreamException; +import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; +import org.apache.dubbo.remoting.http12.h2.Http2CancelableStreamObserver; +import org.apache.dubbo.remoting.http12.h2.Http2MetadataFrame; import org.apache.dubbo.remoting.http12.message.StreamingDecoder; import org.apache.dubbo.remoting.http12.netty4.NettyHttpHeaders; import org.apache.dubbo.rpc.CancellationContext; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.h12.AbstractServerHttpChannelObserver; import io.netty.handler.codec.http2.DefaultHttp2Headers; -public class Http2ServerChannelObserver extends AbstractServerHttpChannelObserver +public class Http2ServerChannelObserver + extends AbstractServerHttpChannelObserver, OUTPUT> implements FlowControlStreamObserver, Http2CancelableStreamObserver { private CancellationContext cancellationContext; - private StreamingDecoder streamingDecoder; + private StreamingDecoder streamingDecoder; private boolean autoRequestN = true; - public Http2ServerChannelObserver(H2StreamChannel h2StreamChannel) { - super(h2StreamChannel); + public Http2ServerChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken.getOutputType()); } - public void setStreamingDecoder(StreamingDecoder streamingDecoder) { + public void setStreamingDecoder(StreamingDecoder streamingDecoder) { this.streamingDecoder = streamingDecoder; } 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 ea959f26346f..c144bdc4ef8b 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 @@ -18,8 +18,8 @@ import org.apache.dubbo.remoting.http12.HttpHeaders; import org.apache.dubbo.remoting.http12.HttpMetadata; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; -import org.apache.dubbo.remoting.http12.h2.Http2ServerChannelObserver; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.ServerStreamObserver; import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; @@ -30,21 +30,25 @@ import java.util.Map; -public class Http2ServerStreamObserver extends Http2ServerChannelObserver +public class Http2ServerStreamObserver extends Http2ServerChannelObserver implements ServerStreamObserver, AttachmentHolder { private final FrameworkModel frameworkModel; private Map attachments; - public Http2ServerStreamObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(h2StreamChannel); + public Http2ServerStreamObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); this.frameworkModel = frameworkModel; } @Override public void setCompression(String compression) { - CompressibleEncoder compressibleEncoder = new CompressibleEncoder(getResponseEncoder()); + CompressibleEncoder compressibleEncoder = + new CompressibleEncoder(getResponseEncoder().delegate()); compressibleEncoder.setCompressor(Compressor.getCompressor(frameworkModel, compression)); setResponseEncoder(compressibleEncoder); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2SseServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2SseServerChannelObserver.java index dfc50c928787..9b5e4433a3a4 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2SseServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2SseServerChannelObserver.java @@ -21,23 +21,29 @@ import org.apache.dubbo.remoting.http12.HttpMetadata; import org.apache.dubbo.remoting.http12.HttpOutputMessage; import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import org.apache.dubbo.remoting.http12.message.ResponseEncoder; import org.apache.dubbo.remoting.http12.message.ServerSentEventEncoder; import org.apache.dubbo.rpc.model.FrameworkModel; -public final class Http2SseServerChannelObserver extends Http2StreamServerChannelObserver { +public final class Http2SseServerChannelObserver + extends Http2StreamServerChannelObserver { - private HttpMessageEncoder originalResponseEncoder; + private ResponseEncoder originalResponseEncoder; - public Http2SseServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(frameworkModel, h2StreamChannel); + public Http2SseServerChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); } @Override public void setResponseEncoder(HttpMessageEncoder responseEncoder) { super.setResponseEncoder(new ServerSentEventEncoder(responseEncoder)); - this.originalResponseEncoder = responseEncoder; + this.originalResponseEncoder = super.createResponseEncoder(responseEncoder); } @Override @@ -47,7 +53,7 @@ protected HttpMetadata encodeHttpMetadata(boolean endStream) { } @Override - protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Throwable { + protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Throwable { if (data instanceof HttpResult) { data = ((HttpResult) data).getBody(); @@ -55,7 +61,7 @@ protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Thr return null; } - HttpOutputMessage message = encodeHttpOutputMessage(data); + HttpOutputMessage message = encodeHttpOutputMessage(data); try { originalResponseEncoder.encode(message.getBody(), data); } catch (Throwable t) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2StreamServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2StreamServerChannelObserver.java index fd8efa6d605a..18df931d2f1f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2StreamServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2StreamServerChannelObserver.java @@ -16,15 +16,19 @@ */ package org.apache.dubbo.rpc.protocol.tri.h12.http2; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; -public class Http2StreamServerChannelObserver extends Http2ServerStreamObserver { +public class Http2StreamServerChannelObserver extends Http2ServerStreamObserver { - public Http2StreamServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(frameworkModel, h2StreamChannel); + public Http2StreamServerChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2UnaryServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2UnaryServerChannelObserver.java index ed15bda6bd19..ef598ed73050 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2UnaryServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2UnaryServerChannelObserver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.http12.HttpHeaders; import org.apache.dubbo.remoting.http12.HttpMetadata; import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2MetadataFrame; import org.apache.dubbo.remoting.http12.netty4.NettyHttpHeaders; @@ -29,18 +30,21 @@ import io.netty.handler.codec.http2.DefaultHttp2Headers; -public class Http2UnaryServerChannelObserver extends Http2StreamServerChannelObserver { +public class Http2UnaryServerChannelObserver extends Http2StreamServerChannelObserver { private static final FluentLogger LOGGER = FluentLogger.of(Http2UnaryServerChannelObserver.class); - public Http2UnaryServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(frameworkModel, h2StreamChannel); + public Http2UnaryServerChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); } @Override protected void doOnNext(Object data) throws Throwable { int statusCode = resolveStatusCode(data); - HttpOutputMessage message = buildMessage(statusCode, data); + HttpOutputMessage message = buildMessage(statusCode, data); HttpMetadata metadata = buildMetadata(statusCode, data, null, message); customizeTrailers(metadata.headers(), null); sendMetadata(metadata); @@ -51,7 +55,7 @@ protected void doOnNext(Object data) throws Throwable { protected void doOnError(Throwable throwable) throws Throwable { int statusCode = resolveErrorStatusCode(throwable); Object data = buildErrorResponse(statusCode, throwable); - HttpOutputMessage message; + HttpOutputMessage message; try { message = buildMessage(statusCode, data); } catch (Throwable t) { @@ -74,7 +78,7 @@ protected void customizeTrailers(HttpHeaders headers, Throwable throwable) { protected void doOnCompleted(Throwable throwable) {} @Override - protected HttpOutputMessage encodeHttpOutputMessage(Object data) { + protected HttpOutputMessage encodeHttpOutputMessage(Object data) { return getHttpChannel().newOutputMessage(true); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/GenericHttp3ServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/GenericHttp3ServerTransportListener.java index 15cd1053af77..2bf868e5f32d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/GenericHttp3ServerTransportListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/GenericHttp3ServerTransportListener.java @@ -17,33 +17,38 @@ package org.apache.dubbo.rpc.protocol.tri.h3; import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; -import org.apache.dubbo.remoting.http12.h2.Http2ServerChannelObserver; import org.apache.dubbo.remoting.http3.Http3TransportListener; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.h12.http2.GenericHttp2ServerTransportListener; +import org.apache.dubbo.rpc.protocol.tri.h12.http2.Http2ServerChannelObserver; -public final class GenericHttp3ServerTransportListener extends GenericHttp2ServerTransportListener - implements Http3TransportListener { +public final class GenericHttp3ServerTransportListener + extends GenericHttp2ServerTransportListener implements Http3TransportListener { public GenericHttp3ServerTransportListener( - H2StreamChannel h2StreamChannel, URL url, FrameworkModel frameworkModel) { - super(h2StreamChannel, url, frameworkModel); + H2StreamChannel h2StreamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + super(h2StreamChannel, url, frameworkModel, typeToken); } @Override - protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { - return new Http3ServerUnaryChannelObserver(getFrameworkModel(), h2StreamChannel); + protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { + return new Http3ServerUnaryChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); } @Override - protected Http2ServerChannelObserver newStreamResponseObserver(H2StreamChannel h2StreamChannel) { - return new Http3ServerUnaryChannelObserver(getFrameworkModel(), h2StreamChannel); + protected Http2ServerChannelObserver newStreamResponseObserver( + H2StreamChannel h2StreamChannel) { + return new Http3ServerUnaryChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); } @Override - protected void doOnData(Http2InputMessage message) { + protected void doOnData(Http2InputMessage message) { if (message.isEndStream()) { onDataCompletion(message); return; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/GenericHttp3ServerTransportListenerFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/GenericHttp3ServerTransportListenerFactory.java index 5fefeb7b7bfa..312feadeb859 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/GenericHttp3ServerTransportListenerFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/GenericHttp3ServerTransportListenerFactory.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory; import org.apache.dubbo.remoting.http3.Http3TransportListener; @@ -27,8 +28,12 @@ public class GenericHttp3ServerTransportListenerFactory implements Http3ServerTransportListenerFactory { @Override - public Http3TransportListener newInstance(H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel) { - return new GenericHttp3ServerTransportListener(streamChannel, url, frameworkModel); + public Http3TransportListener newInstance( + H2StreamChannel streamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + return new GenericHttp3ServerTransportListener<>(streamChannel, url, frameworkModel, typeToken); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3ServerUnaryChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3ServerUnaryChannelObserver.java index d1b68b6df690..13ccd0213125 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3ServerUnaryChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3ServerUnaryChannelObserver.java @@ -17,14 +17,19 @@ package org.apache.dubbo.rpc.protocol.tri.h3; import org.apache.dubbo.remoting.http12.HttpMetadata; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.h12.http2.Http2UnaryServerChannelObserver; -public final class Http3ServerUnaryChannelObserver extends Http2UnaryServerChannelObserver { +public final class Http3ServerUnaryChannelObserver + extends Http2UnaryServerChannelObserver { - public Http3ServerUnaryChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(frameworkModel, h2StreamChannel); + public Http3ServerUnaryChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerChannelObserver.java index 82a01d3946a0..4dcf9ff47293 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerChannelObserver.java @@ -17,15 +17,20 @@ package org.apache.dubbo.rpc.protocol.tri.h3.grpc; import org.apache.dubbo.remoting.http12.HttpMetadata; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcStreamServerChannelObserver; import org.apache.dubbo.rpc.protocol.tri.h3.Helper; -public final class GrpcHttp3ServerChannelObserver extends GrpcStreamServerChannelObserver { +public final class GrpcHttp3ServerChannelObserver + extends GrpcStreamServerChannelObserver { - public GrpcHttp3ServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(frameworkModel, h2StreamChannel); + public GrpcHttp3ServerChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListener.java index 1772d875eb48..f3dd50282092 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListener.java @@ -17,32 +17,38 @@ package org.apache.dubbo.rpc.protocol.tri.h3.grpc; import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; -import org.apache.dubbo.remoting.http12.h2.Http2ServerChannelObserver; import org.apache.dubbo.remoting.http3.Http3TransportListener; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcHttp2ServerTransportListener; +import org.apache.dubbo.rpc.protocol.tri.h12.http2.Http2ServerChannelObserver; -public final class GrpcHttp3ServerTransportListener extends GrpcHttp2ServerTransportListener - implements Http3TransportListener { +public final class GrpcHttp3ServerTransportListener + extends GrpcHttp2ServerTransportListener implements Http3TransportListener { - public GrpcHttp3ServerTransportListener(H2StreamChannel h2StreamChannel, URL url, FrameworkModel frameworkModel) { - super(h2StreamChannel, url, frameworkModel); + public GrpcHttp3ServerTransportListener( + H2StreamChannel h2StreamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + super(h2StreamChannel, url, frameworkModel, typeToken); } @Override - protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { - return new GrpcHttp3UnaryServerChannelObserver(getFrameworkModel(), h2StreamChannel); + protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { + return new GrpcHttp3UnaryServerChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); } @Override - protected Http2ServerChannelObserver newStreamResponseObserver(H2StreamChannel h2StreamChannel) { - return new GrpcHttp3ServerChannelObserver(getFrameworkModel(), h2StreamChannel); + protected Http2ServerChannelObserver newStreamResponseObserver( + H2StreamChannel h2StreamChannel) { + return new GrpcHttp3ServerChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); } @Override - protected void doOnData(Http2InputMessage message) { + protected void doOnData(Http2InputMessage message) { if (message.isEndStream()) { onDataCompletion(message); return; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java index 9d0e3437797a..b9a392548ef1 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory; import org.apache.dubbo.remoting.http3.Http3TransportListener; @@ -29,8 +30,12 @@ public class GrpcHttp3ServerTransportListenerFactory implements Http3ServerTransportListenerFactory { @Override - public Http3TransportListener newInstance(H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel) { - return new GrpcHttp3ServerTransportListener(streamChannel, url, frameworkModel); + public Http3TransportListener newInstance( + H2StreamChannel streamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + return new GrpcHttp3ServerTransportListener<>(streamChannel, url, frameworkModel, typeToken); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3UnaryServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3UnaryServerChannelObserver.java index 88dcfb5afe1a..9770909e0683 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3UnaryServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3UnaryServerChannelObserver.java @@ -17,15 +17,19 @@ package org.apache.dubbo.rpc.protocol.tri.h3.grpc; import org.apache.dubbo.remoting.http12.HttpMetadata; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcUnaryServerChannelObserver; import org.apache.dubbo.rpc.protocol.tri.h3.Helper; -public class GrpcHttp3UnaryServerChannelObserver extends GrpcUnaryServerChannelObserver { +public class GrpcHttp3UnaryServerChannelObserver extends GrpcUnaryServerChannelObserver { - public GrpcHttp3UnaryServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(frameworkModel, h2StreamChannel); + public GrpcHttp3UnaryServerChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractTripleClientStream.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractTripleClientStream.java index 89927fed3ef6..46b2fb4786e0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractTripleClientStream.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractTripleClientStream.java @@ -21,6 +21,7 @@ import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.remoting.http12.HttpHeaderNames; +import org.apache.dubbo.remoting.http12.message.StreamingDecoder.FragmentListener; import org.apache.dubbo.rpc.TriRpcStatus; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.ClassLoadUtil; @@ -32,8 +33,7 @@ import org.apache.dubbo.rpc.protocol.tri.command.HeaderQueueCommand; 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.h12.grpc.GrpcByteBufStreamingDecoder; import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcUtils; import org.apache.dubbo.rpc.protocol.tri.transport.AbstractH2TransportListener; import org.apache.dubbo.rpc.protocol.tri.transport.H2TransportListener; @@ -77,11 +77,11 @@ public abstract class AbstractTripleClientStream extends AbstractStream implemen private final ClientStream.Listener listener; protected final TripleWriteQueue writeQueue; - private Deframer deframer; private final Channel parent; private final TripleStreamChannelFuture streamChannelFuture; private boolean halfClosed; private boolean rst; + private GrpcByteBufStreamingDecoder decoder; private boolean isReturnTriException = false; @@ -158,12 +158,12 @@ public SSLSession getSslSession() { } @Override - public ChannelFuture sendMessage(byte[] message, int compressFlag) { + public ChannelFuture sendMessage(ByteBuf message) { ChannelFuture checkResult = preCheck(); if (!checkResult.isSuccess()) { return checkResult; } - final DataQueueCommand cmd = DataQueueCommand.create(streamChannelFuture, message, false, compressFlag); + final DataQueueCommand cmd = DataQueueCommand.create(streamChannelFuture, message, false); return this.writeQueue.enqueueFuture(cmd, parent.eventLoop()).addListener(future -> { if (!future.isSuccess()) { cancelByLocal(TriRpcStatus.INTERNAL @@ -176,7 +176,7 @@ public ChannelFuture sendMessage(byte[] message, int compressFlag) { @Override public void request(int n) { - deframer.request(n); + decoder.request(n); } @Override @@ -291,17 +291,19 @@ void onHeaderReceived(Http2Headers headers) { } } } - TriDecoder.Listener listener = new TriDecoder.Listener() { + decoder = new GrpcByteBufStreamingDecoder(); + decoder.setFragmentListener(new FragmentListener() { @Override - public void onRawMessage(byte[] data) { - AbstractTripleClientStream.this.listener.onMessage(data, isReturnTriException); + public void onFragmentMessage(ByteBuf rawMessage) { + AbstractTripleClientStream.this.listener.onMessage(rawMessage, isReturnTriException); } - public void close() { + @Override + public void onClose() { finishProcess(statusFromTrailers(trailers), trailers, isReturnTriException); } - }; - deframer = new TriDecoder(decompressor, listener); + }); + decoder.setDeCompressor(decompressor); AbstractTripleClientStream.this.listener.onStart(); } @@ -317,10 +319,10 @@ void onTrailersReceived(Http2Headers trailers) { transportError = transportError.appendDescription("trailers: " + trailers); status = transportError; } - if (deframer == null) { + if (decoder == null) { finishProcess(status, trailers, false); } else { - deframer.close(); + decoder.close(); } } @@ -458,7 +460,7 @@ private void doOnData(ByteBuf data, boolean endStream) { handleH2TransportError(TriRpcStatus.INTERNAL.withDescription("headers not received before payload")); return; } - deframer.deframe(data); + decoder.decode(data); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/ClientStream.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/ClientStream.java index 94bff9865d37..835587105927 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/ClientStream.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/ClientStream.java @@ -20,6 +20,7 @@ import java.util.Map; +import io.netty.buffer.ByteBuf; import io.netty.util.concurrent.Future; /** @@ -66,7 +67,7 @@ default void onComplete( * @param message message to send to remote peer * @return future to callback when send message is done */ - Future sendMessage(byte[] message, int compressFlag); + Future sendMessage(ByteBuf message); /** * No more data will be sent, half close this stream to wait server response. diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/Stream.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/Stream.java index 2ff8d7c83157..affa1958e3a5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/Stream.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/Stream.java @@ -22,6 +22,7 @@ import java.net.SocketAddress; +import io.netty.buffer.ByteBuf; import io.netty.handler.codec.http2.Http2Headers; import io.netty.util.concurrent.Future; @@ -43,7 +44,7 @@ interface Listener { * * @param message message received from remote peer */ - void onMessage(byte[] message, boolean isReturnTriException); + void onMessage(ByteBuf message, boolean isReturnTriException); /** * Callback when receive cancel signal. diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListener.java index e43367d7b793..19d30418f3f2 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListener.java @@ -18,32 +18,37 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.remoting.http12.HttpHeaders; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2Header; import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; -import org.apache.dubbo.remoting.http12.h2.Http2ServerChannelObserver; -import org.apache.dubbo.remoting.http12.message.StreamingDecoder; -import org.apache.dubbo.remoting.websocket.FinalFragmentStreamingDecoder; import org.apache.dubbo.remoting.websocket.WebSocketHeaderNames; import org.apache.dubbo.remoting.websocket.WebSocketTransportListener; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.MethodDescriptor.RpcType; import org.apache.dubbo.rpc.protocol.tri.h12.http2.GenericHttp2ServerTransportListener; +import org.apache.dubbo.rpc.protocol.tri.h12.http2.Http2ServerChannelObserver; import java.util.concurrent.Executor; -public class DefaultWebSocketServerTransportListener extends GenericHttp2ServerTransportListener - implements WebSocketTransportListener { +public class DefaultWebSocketServerTransportListener + extends GenericHttp2ServerTransportListener + implements WebSocketTransportListener { private boolean autoClose = false; public DefaultWebSocketServerTransportListener( - H2StreamChannel h2StreamChannel, URL url, FrameworkModel frameworkModel) { - super(h2StreamChannel, url, frameworkModel); + H2StreamChannel h2StreamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + super(h2StreamChannel, url, frameworkModel, typeToken); } @Override - protected void onBeforeMetadata(Http2Header metadata) {} + protected void onBeforeMetadata(Http2Header metadata) { + // no op + } @Override protected Executor initializeExecutor(URL url, Http2Header metadata) { @@ -56,22 +61,19 @@ protected void onPrepareMetadata(Http2Header metadata) { } @Override - protected StreamingDecoder newStreamingDecoder() { - return new FinalFragmentStreamingDecoder(); - } - - @Override - protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { - return new WebSocketServerChannelObserver(getFrameworkModel(), h2StreamChannel); + protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { + return new WebSocketServerChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); } @Override - protected Http2ServerChannelObserver newStreamResponseObserver(H2StreamChannel h2StreamChannel) { - return new WebSocketServerChannelObserver(getFrameworkModel(), h2StreamChannel); + protected Http2ServerChannelObserver newStreamResponseObserver( + H2StreamChannel h2StreamChannel) { + return new WebSocketServerChannelObserver<>(getFrameworkModel(), h2StreamChannel, getTypeToken()); } @Override - protected Http2ServerChannelObserver prepareResponseObserver(Http2ServerChannelObserver responseObserver) { + protected Http2ServerChannelObserver prepareResponseObserver( + Http2ServerChannelObserver responseObserver) { responseObserver.addTrailersCustomizer(this::customizeWebSocketStatus); return super.prepareResponseObserver(responseObserver); } @@ -91,7 +93,7 @@ protected void prepareStreamServerCall() { } @Override - protected void onDataCompletion(Http2InputMessage message) { + protected void onDataCompletion(Http2InputMessage message) { if (autoClose) { getStreamingDecoder().close(); return; @@ -99,6 +101,11 @@ protected void onDataCompletion(Http2InputMessage message) { super.onDataCompletion(message); } + @Override + protected String protocol() { + return "websocket"; + } + private void customizeWebSocketStatus(HttpHeaders httpHeaders, Throwable throwable) { if (throwable != null) { httpHeaders.set(WebSocketHeaderNames.WEBSOCKET_MESSAGE.getName(), throwable.getMessage()); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListenerFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListenerFactory.java index fd5c331f5e65..d60e9d11a100 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListenerFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListenerFactory.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.websocket; import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory; import org.apache.dubbo.remoting.websocket.WebSocketTransportListener; @@ -28,8 +29,11 @@ public class DefaultWebSocketServerTransportListenerFactory implements WebSocket new DefaultWebSocketServerTransportListenerFactory(); @Override - public WebSocketTransportListener newInstance( - H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel) { - return new DefaultWebSocketServerTransportListener(streamChannel, url, frameworkModel); + public WebSocketTransportListener newInstance( + H2StreamChannel streamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + return new DefaultWebSocketServerTransportListener<>(streamChannel, url, frameworkModel, typeToken); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketByteBufInputMessageHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketByteBufInputMessageHandler.java new file mode 100644 index 000000000000..659f92bb3844 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketByteBufInputMessageHandler.java @@ -0,0 +1,36 @@ +/* + * 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.websocket; + +import org.apache.dubbo.remoting.http12.message.StreamingDecoder; +import org.apache.dubbo.remoting.websocket.FinalFragmentStreamingDecoder; +import org.apache.dubbo.rpc.protocol.tri.ByteBufInputMessageHandler; + +import io.netty.buffer.ByteBuf; + +public class WebSocketByteBufInputMessageHandler extends ByteBufInputMessageHandler { + + @Override + public StreamingDecoder createStreamingDecoder() { + return new FinalFragmentStreamingDecoder(); + } + + @Override + public String supportProtocol() { + return "websocket"; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketServerChannelObserver.java index 3590dbc0269b..678b296c1711 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketServerChannelObserver.java @@ -17,20 +17,24 @@ package org.apache.dubbo.rpc.protocol.tri.websocket; import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.h12.http2.Http2StreamServerChannelObserver; -public class WebSocketServerChannelObserver extends Http2StreamServerChannelObserver { +public class WebSocketServerChannelObserver extends Http2StreamServerChannelObserver { - protected WebSocketServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { - super(frameworkModel, h2StreamChannel); + protected WebSocketServerChannelObserver( + FrameworkModel frameworkModel, + H2StreamChannel h2StreamChannel, + MessageTypeToken typeToken) { + super(frameworkModel, h2StreamChannel, typeToken); } @Override protected void doOnNext(Object data) throws Throwable { int statusCode = resolveStatusCode(data); - HttpOutputMessage httpOutputMessage = buildMessage(statusCode, data); + HttpOutputMessage httpOutputMessage = buildMessage(statusCode, data); sendMessage(httpOutputMessage); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.InputMessageHandler b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.InputMessageHandler new file mode 100644 index 000000000000..3ba7ff4014df --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.InputMessageHandler @@ -0,0 +1,6 @@ +http-inputStream=org.apache.dubbo.rpc.protocol.tri.InputStreamMessageHandler +grpc-inputStream=org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcInputStreamMessageHandler + +http-byteBuf=org.apache.dubbo.rpc.protocol.tri.ByteBufInputMessageHandler +grpc-byteBuf=org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcByteBufInputMessageHandler +websocket-byteBuf=org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketByteBufInputMessageHandler diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.OutputMessageHandler b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.OutputMessageHandler new file mode 100644 index 000000000000..3805eac422ae --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.OutputMessageHandler @@ -0,0 +1,2 @@ +inputStream=org.apache.dubbo.rpc.protocol.tri.OutputStreamMessageHandler +byteBuf=org.apache.dubbo.rpc.protocol.tri.ByteBufOutputMessageHandler diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoderTest.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoderTest.java deleted file mode 100644 index 40e793fcb3fb..000000000000 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoderTest.java +++ /dev/null @@ -1,52 +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.frame; - -import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -class TriDecoderTest { - - @Test - void decode() { - final RecordListener listener = new RecordListener(); - TriDecoder decoder = new TriDecoder(DeCompressor.NONE, listener); - final ByteBuf buf = Unpooled.buffer(); - buf.writeByte(0); - buf.writeInt(1); - buf.writeByte(2); - decoder.deframe(buf); - final ByteBuf buf2 = Unpooled.buffer(); - buf2.writeByte(0); - buf2.writeInt(2); - buf2.writeByte(2); - buf2.writeByte(3); - decoder.deframe(buf2); - Assertions.assertEquals(0, listener.dataCount); - decoder.request(1); - Assertions.assertEquals(1, listener.dataCount); - Assertions.assertEquals(1, listener.lastData.length); - decoder.request(1); - Assertions.assertEquals(2, listener.dataCount); - Assertions.assertEquals(2, listener.lastData.length); - decoder.close(); - } -} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/MockClientStreamListener.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/MockClientStreamListener.java index 35219f1f05bf..c7718526c192 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/MockClientStreamListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/MockClientStreamListener.java @@ -20,10 +20,12 @@ import java.util.Map; +import io.netty.buffer.ByteBuf; + public class MockClientStreamListener implements ClientStream.Listener { public TriRpcStatus status; - public byte[] message; + public ByteBuf message; public boolean started; @Override @@ -40,7 +42,7 @@ public void onComplete(TriRpcStatus status, Map attachments) { public void onClose() {} @Override - public void onMessage(byte[] message, boolean isNeedReturnException) { + public void onMessage(ByteBuf message, boolean isNeedReturnException) { this.message = message; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleClientStreamTest.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleClientStreamTest.java index fa71ca1fa9bc..c9516bef6314 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleClientStreamTest.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleClientStreamTest.java @@ -102,7 +102,7 @@ void progress() { verify(writeQueue).enqueueFuture(any(HeaderQueueCommand.class), any(Executor.class)); // no other commands verify(writeQueue).enqueue(any(QueuedCommand.class)); - stream.sendMessage(new byte[0], 0); + stream.sendMessage(Unpooled.wrappedBuffer(new byte[] {0})); verify(writeQueue).enqueueFuture(any(DataQueueCommand.class), any(Executor.class)); verify(writeQueue, times(2)).enqueueFuture(any(QueuedCommand.class), any(Executor.class)); stream.halfClose(); @@ -124,6 +124,6 @@ void progress() { byte[] data = new byte[] {0, 0, 0, 0, 1, 1}; final ByteBuf buf = Unpooled.wrappedBuffer(data); transportListener.onData(buf, false); - Assertions.assertEquals(1, listener.message.length); + Assertions.assertEquals(1, listener.message.readableBytes()); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/MockH2StreamChannel.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/MockH2StreamChannel.java index d9d30a64b1e8..6110d519f98d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/MockH2StreamChannel.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/MockH2StreamChannel.java @@ -28,7 +28,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; -public class MockH2StreamChannel implements H2StreamChannel { +public class MockH2StreamChannel implements H2StreamChannel { private HttpMetadata httpMetadata; private final List bodies = new ArrayList<>(); @@ -44,7 +44,7 @@ public CompletableFuture writeHeader(HttpMetadata httpMetadata) { } @Override - public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { bodies.add(httpOutputMessage.getBody()); return CompletableFuture.completedFuture(null); } @@ -68,7 +68,7 @@ public CompletableFuture writeResetFrame(long errorCode) { } @Override - public Http2OutputMessage newOutputMessage(boolean endStream) { + public Http2OutputMessage newOutputMessage(boolean endStream) { return new MockHttp2OutputMessage(endStream); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/MockHttp2OutputMessage.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/MockHttp2OutputMessage.java index 18fd78158a2a..42bf99c4ce24 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/MockHttp2OutputMessage.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/MockHttp2OutputMessage.java @@ -21,7 +21,7 @@ import java.io.ByteArrayOutputStream; import java.io.OutputStream; -public class MockHttp2OutputMessage implements Http2OutputMessage { +public class MockHttp2OutputMessage implements Http2OutputMessage { private final OutputStream outputStream; private final boolean endStream; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestRunnerImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestRunnerImpl.java index 439b96fb3297..1cc776fd09d2 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestRunnerImpl.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestRunnerImpl.java @@ -24,6 +24,7 @@ import org.apache.dubbo.config.Constants; import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame; import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder; @@ -46,6 +47,8 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.LinkedHashMap; import java.util.List; @@ -53,7 +56,8 @@ final class TestRunnerImpl implements TestRunner { - static final Http2InputMessage END = new Http2InputMessageFrame(new ByteArrayInputStream(new byte[0]), true); + static final Http2InputMessage END = + new Http2InputMessageFrame(new ByteArrayInputStream(new byte[0]), true); private final FrameworkModel frameworkModel; private final ApplicationModel applicationModel; @@ -96,7 +100,8 @@ private void registerProvider(TProvider provider, Protocol protocol, Prox public TestResponse run(TestRequest request) { MockH2StreamChannel channel = new MockH2StreamChannel(); URL url = new URL(TestProtocol.NAME, TestProtocol.HOST, TestProtocol.PORT, request.getProviderParams()); - TestServerTransportListener listener = new TestServerTransportListener(channel, url, frameworkModel); + TestServerTransportListener listener = new TestServerTransportListener<>( + channel, url, frameworkModel, new MessageTypeToken() {}); if (request.getMethod() == null) { request.setMethod(HttpMethods.GET.name()); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestServerTransportListener.java index 255be42d6752..29fe8ab655cc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestServerTransportListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestServerTransportListener.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.test; import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.MessageTypeToken; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http12.h2.Http2Header; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -24,10 +25,14 @@ import java.util.concurrent.Executor; -public class TestServerTransportListener extends GenericHttp2ServerTransportListener { +public class TestServerTransportListener extends GenericHttp2ServerTransportListener { - public TestServerTransportListener(H2StreamChannel h2StreamChannel, URL url, FrameworkModel frameworkModel) { - super(h2StreamChannel, url, frameworkModel); + public TestServerTransportListener( + H2StreamChannel h2StreamChannel, + URL url, + FrameworkModel frameworkModel, + MessageTypeToken typeToken) { + super(h2StreamChannel, url, frameworkModel, typeToken); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/transport/WriteQueueTest.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/transport/WriteQueueTest.java index 22e8452463f7..ee2b518b6c84 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/transport/WriteQueueTest.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/transport/WriteQueueTest.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelPromise; import io.netty.channel.DefaultEventLoop; @@ -82,8 +83,9 @@ void test() throws Exception { TripleStreamChannelFuture tripleStreamChannelFuture = new TripleStreamChannelFuture(embeddedChannel); writeQueue.enqueue(HeaderQueueCommand.createHeaders(tripleStreamChannelFuture, new DefaultHttp2Headers()) .channel(channel)); - writeQueue.enqueue(DataQueueCommand.create(tripleStreamChannelFuture, new byte[0], false, 0) - .channel(channel)); + writeQueue.enqueue( + DataQueueCommand.create(tripleStreamChannelFuture, Unpooled.wrappedBuffer(new byte[] {0}), false) + .channel(channel)); TriRpcStatus status = TriRpcStatus.UNKNOWN.withCause(new RpcException()).withDescription("Encode Response data error"); writeQueue.enqueue(CancelQueueCommand.createCommand(tripleStreamChannelFuture, Http2Error.CANCEL)