Merge branch 'master' into add-tri-samples

# Conflicts:
#	dubbo-samples-triple/pom.xml

fix conflicts
diff --git a/dubbo-samples-triple/README.MD b/dubbo-samples-triple/README.MD
new file mode 100644
index 0000000..bb53905
--- /dev/null
+++ b/dubbo-samples-triple/README.MD
@@ -0,0 +1,37 @@
+## Triple-Samples
+
+### For beginners
+
+1. Start a zookeeper or config other registry in `org.apache.dubbo.sample.tri.ApiProvider`
+   and `org.apache.dubbo.sample.tri.ApiConsumer`
+2. Build with `mvn clean install` to generate protobuf classes.
+3. Run `org.apache.dubbo.sample.tri.ApiProvider`
+4. Run `org.apache.dubbo.sample.tri.ApiConsumer`
+
+### For dubbo2 or non-prototbuf users
+Run `org.apache.dubbo.sample.tri.ApiWrapperProvider` and `org.apache.dubbo.sample.tri.ApiWrapperConsumer`.
+
+Dubbo3 will wrap request and response with a protobuf wrapper automatically, so it is still compatible with GRPC.
+
+### For Dubbo developers
+Code under `test` folder is a general interoperation test suite for both Dubbo/Dubbo and Dubbo/GRPC.
+
+#### Dubbo/Dubbo test
+1. Run `org.apache.dubbo.sample.tri.TriProvider`
+2. Run `org.apache.dubbo.sample.tri.TriPbConsumerTest` , `org.apache.dubbo.sample.tri.TriWrapConsumerTest`  and `org.apache.dubbo.sample.tri.TriGenericTest`
+
+#### DUbbo/GRPC test
+
+##### GRPC --> Dubbo
+
+1. Run `org.apache.dubbo.sample.tri.TriProvider`
+2. Run `org.apache.dubbo.sample.tri.grpc.GrpcConsumerTest`
+
+##### Dubbo --> GRPC
+
+1. Run `org.apache.dubbo.sample.tri.grpc.GrpcProvider`
+2. Run `org.apache.dubbo.sample.tri.TriPbConsumerTest`
+
+
+
+
diff --git a/dubbo-samples-triple/pom.xml b/dubbo-samples-triple/pom.xml
index 83519ec..cd35e4a 100644
--- a/dubbo-samples-triple/pom.xml
+++ b/dubbo-samples-triple/pom.xml
@@ -31,14 +31,16 @@
     <properties>
         <source.level>1.8</source.level>
         <target.level>1.8</target.level>
+        <dubbo.version>3.0.3-SNAPSHOT</dubbo.version>
+        <grpc.version>1.40.1</grpc.version>
         <dubbo.version>3.0.2.1</dubbo.version>
         <junit.version>4.12</junit.version>
         <spring-test.version>4.3.16.RELEASE</spring-test.version>
         <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
         <maven-failsafe-plugin.version>2.21.0</maven-failsafe-plugin.version>
         <spring-boot.version>1.5.13.RELEASE</spring-boot.version>
-        <grpc.version>1.19.0</grpc.version>
         <protoc.version>3.7.1</protoc.version>
+        <dubbo.compiler.version>0.0.4-SNAPSHOT</dubbo.compiler.version>
     </properties>
 
     <dependencies>
@@ -59,6 +61,12 @@
             <type>pom</type>
         </dependency>
         <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-all</artifactId>
+            <version>${grpc.version}</version>
+<!--            <scope>test</scope>-->
+        </dependency>
+        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>${junit.version}</version>
@@ -110,15 +118,26 @@
                 <artifactId>protobuf-maven-plugin</artifactId>
                 <version>0.6.1</version>
                 <configuration>
-                    <protocArtifact>com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}</protocArtifact>
-                    <pluginId>triple-java</pluginId>
-                    <outputDirectory>build/generated/source/proto/main/java</outputDirectory>
+                    <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
+                    <pluginId>grpc-java</pluginId>
+                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
+                    <protocPlugins>
+                        <protocPlugin>
+                            <id>dubbo</id>
+                            <groupId>org.apache.dubbo</groupId>
+                            <artifactId>dubbo-compiler</artifactId>
+                            <version>${dubbo.compiler.version}</version>
+                            <mainClass>org.apache.dubbo.gen.dubbo.Dubbo3Generator</mainClass>
+                        </protocPlugin>
+                    </protocPlugins>
                 </configuration>
                 <executions>
                     <execution>
                         <goals>
                             <goal>compile</goal>
                             <goal>test-compile</goal>
+                            <goal>compile-custom</goal>
+                            <goal>test-compile-custom</goal>
                         </goals>
                     </execution>
                 </executions>
@@ -132,23 +151,6 @@
                     <target>${target.level}</target>
                 </configuration>
             </plugin>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>build/generated/source/proto/main/java</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
     </build>
 
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiWrapperConsumer.java b/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiWrapperConsumer.java
deleted file mode 100644
index ce40f92..0000000
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiWrapperConsumer.java
+++ /dev/null
@@ -1,46 +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 com.apache.dubbo.sample.basic;
-
-import org.apache.dubbo.config.ApplicationConfig;
-import org.apache.dubbo.config.ReferenceConfig;
-import org.apache.dubbo.config.RegistryConfig;
-import org.apache.dubbo.config.bootstrap.DubboBootstrap;
-
-public class ApiWrapperConsumer {
-    public static void main(String[] args) {
-        ReferenceConfig<IGreeter2> ref = new ReferenceConfig<>();
-        ref.setInterface(IGreeter2.class);
-        ref.setCheck(false);
-        ref.setProtocol("tri");
-        ref.setLazy(true);
-
-        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
-        bootstrap.application(new ApplicationConfig("demo-consumer"))
-                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
-                .reference(ref)
-                .start();
-
-        final IGreeter2 iGreeter = ref.get();
-        System.out.println("dubbo ref started");
-        long st = System.currentTimeMillis();
-        String reply = iGreeter.sayHello0("haha");
-        // 4MB response
-        System.out.println("Reply len:" + reply.length() + " cost:" + (System.currentTimeMillis() - st));
-    }
-}
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter1Impl.java b/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter1Impl.java
deleted file mode 100644
index 11a3129..0000000
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter1Impl.java
+++ /dev/null
@@ -1,30 +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 com.apache.dubbo.sample.basic;
-
-import org.apache.dubbo.hello.HelloReply;
-import org.apache.dubbo.hello.HelloRequest;
-
-public class IGreeter1Impl implements IGreeter {
-    @Override
-    public HelloReply sayHello(HelloRequest request) {
-        return HelloReply.newBuilder()
-                .setMessage(request.getName())
-                .build();
-    }
-}
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter2.java b/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter2.java
deleted file mode 100644
index bd91137..0000000
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter2.java
+++ /dev/null
@@ -1,28 +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 com.apache.dubbo.sample.basic;
-
-public interface IGreeter2 {
-    /**
-     * <pre>
-     *  Sends a greeting
-     * </pre>
-     */
-    String sayHello0(String request);
-
-}
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter2Impl.java b/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter2Impl.java
deleted file mode 100644
index 9010e0a..0000000
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter2Impl.java
+++ /dev/null
@@ -1,30 +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 com.apache.dubbo.sample.basic;
-
-public class IGreeter2Impl implements IGreeter2 {
-    @Override
-    public String sayHello0(String request) {
-        StringBuilder respBuilder = new StringBuilder(request);
-        for (int i = 0; i < 20; i++) {
-            respBuilder.append(respBuilder);
-        }
-        request = respBuilder.toString();
-        return request;
-    }
-}
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiConsumer.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiConsumer.java
similarity index 64%
rename from dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiConsumer.java
rename to dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiConsumer.java
index 6d18ae8..a256767 100644
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiConsumer.java
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiConsumer.java
@@ -15,9 +15,10 @@
  *  limitations under the License.
  */
 
-package com.apache.dubbo.sample.basic;
+package org.apache.dubbo.sample.tri;
 
 import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.stream.StreamObserver;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ReferenceConfig;
 import org.apache.dubbo.config.RegistryConfig;
@@ -28,8 +29,10 @@
 import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
-public class ApiConsumer {
-    public static void main(String[] args) throws IOException {
+class ApiConsumer {
+    private final IGreeter delegate;
+
+    ApiConsumer() {
         ReferenceConfig<IGreeter> ref = new ReferenceConfig<>();
         ref.setInterface(IGreeter.class);
         ref.setCheck(false);
@@ -41,15 +44,41 @@
 
         DubboBootstrap bootstrap = DubboBootstrap.getInstance();
         bootstrap.application(new ApplicationConfig("demo-consumer"))
-                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
                 .reference(ref)
                 .start();
 
-        final IGreeter iGreeter = ref.get();
+        this.delegate = ref.get();
+    }
 
-        System.out.println("dubbo ref started");
+    public static void main(String[] args) throws IOException {
+        final ApiConsumer consumer = new ApiConsumer();
+        System.out.println("dubbo triple consumer started");
+        consumer.unaryHello();
+        consumer.stream();
+        consumer.serverStream();
+        System.in.read();
+    }
+
+    public void serverStream() {
+        delegate.sayHelloServerStream(HelloRequest.newBuilder()
+                .setName("request")
+                .build(), new StdoutStreamObserver<>("serverStream"));
+    }
+
+    public void stream() {
+        final StreamObserver<HelloRequest> request = delegate.sayHelloStream(new StdoutStreamObserver<>("stream"));
+        for (int i = 0; i < 10; i++) {
+            request.onNext(HelloRequest.newBuilder()
+                    .setName("request")
+                    .build());
+        }
+        request.onCompleted();
+    }
+
+    public void unaryHello() {
         try {
-            final HelloReply reply = iGreeter.sayHello(HelloRequest.newBuilder()
+            final HelloReply reply = delegate.sayHello(HelloRequest.newBuilder()
                     .setName("name")
                     .build());
             TimeUnit.SECONDS.sleep(1);
@@ -57,6 +86,6 @@
         } catch (Throwable t) {
             t.printStackTrace();
         }
-        System.in.read();
     }
+
 }
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiProvider.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiProvider.java
similarity index 90%
rename from dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiProvider.java
rename to dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiProvider.java
index df90b39..b54984b 100644
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiProvider.java
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiProvider.java
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package com.apache.dubbo.sample.basic;
+package org.apache.dubbo.sample.tri;
 
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.config.ApplicationConfig;
@@ -24,7 +24,7 @@
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 
-public class ApiProvider {
+class ApiProvider {
     public static void main(String[] args) {
         ServiceConfig<IGreeter> service = new ServiceConfig<>();
         service.setInterface(IGreeter.class);
@@ -32,8 +32,8 @@
 
         DubboBootstrap bootstrap = DubboBootstrap.getInstance();
         bootstrap.application(new ApplicationConfig("demo-provider"))
-                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
-                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, TriSampleConstants.SERVER_PORT))
                 .service(service)
                 .start()
                 .await();
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiWrapperConsumer.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiWrapperConsumer.java
new file mode 100644
index 0000000..d595fb8
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiWrapperConsumer.java
@@ -0,0 +1,70 @@
+/*
+ *  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.sample.tri;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+
+class ApiWrapperConsumer {
+    private final IWrapperGreeter delegate;
+
+    public ApiWrapperConsumer() {
+        ReferenceConfig<IWrapperGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(IWrapperGreeter.class);
+        ref.setCheck(false);
+        ref.setTimeout(3000);
+        ref.setProtocol("tri");
+        ref.setLazy(true);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
+                .reference(ref)
+                .start();
+        this.delegate = ref.get();
+    }
+
+    public static void main(String[] args) {
+        final ApiWrapperConsumer consumer = new ApiWrapperConsumer();
+        System.out.println("dubbo triple wrapper consuemr started");
+        consumer.sayHelloUnary();
+        consumer.sayHelloStream();
+        consumer.sayHelloServerStream();
+    }
+
+    public void sayHelloUnary() {
+        System.out.println(delegate.sayHello("unary"));
+    }
+
+    public void sayHelloServerStream() {
+        delegate.sayHelloServerStream("server stream", new StdoutStreamObserver<>("sayHelloServerStream"));
+
+    }
+
+    public void sayHelloStream() {
+        final StreamObserver<String> request = delegate.sayHelloStream(new StdoutStreamObserver<>("sayHelloStream"));
+        for (int i = 0; i < 10; i++) {
+            request.onNext("stream request");
+        }
+        request.onCompleted();
+    }
+
+}
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiWrapperProvider.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiWrapperProvider.java
similarity index 82%
rename from dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiWrapperProvider.java
rename to dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiWrapperProvider.java
index ce979fb..fb0862f 100644
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiWrapperProvider.java
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ApiWrapperProvider.java
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package com.apache.dubbo.sample.basic;
+package org.apache.dubbo.sample.tri;
 
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.config.ApplicationConfig;
@@ -24,16 +24,16 @@
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 
-public class ApiWrapperProvider {
+class ApiWrapperProvider {
     public static void main(String[] args) {
-        ServiceConfig<IGreeter2> service = new ServiceConfig<>();
-        service.setInterface(IGreeter2.class);
+        ServiceConfig<IWrapperGreeter> service = new ServiceConfig<>();
+        service.setInterface(IWrapperGreeter.class);
         service.setRef(new IGreeter2Impl());
 
         DubboBootstrap bootstrap = DubboBootstrap.getInstance();
         bootstrap.application(new ApplicationConfig("demo-provider"))
-                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
-                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, TriSampleConstants.SERVER_PORT))
                 .service(service)
                 .start()
                 .await();
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/BizErrorCodeClientFilter.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/BizErrorCodeClientFilter.java
new file mode 100644
index 0000000..93f9b3a
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/BizErrorCodeClientFilter.java
@@ -0,0 +1,44 @@
+/*
+ *  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.sample.tri;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.rpc.BaseFilter;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
+
+@Activate(group = {CommonConstants.CONSUMER})
+public class BizErrorCodeClientFilter implements ClusterFilter, BaseFilter.Listener {
+    @Override
+    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
+        return invoker.invoke(invocation);
+    }
+
+    @Override
+    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
+        appResponse.getObjectAttachment("biz-err-code");
+    }
+
+    @Override
+    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
+    }
+}
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/EchoStreamObserver.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/EchoStreamObserver.java
new file mode 100644
index 0000000..509a973
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/EchoStreamObserver.java
@@ -0,0 +1,36 @@
+package org.apache.dubbo.sample.tri;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+
+import java.util.function.Function;
+
+/**
+ * @author earthchen
+ * @date 2021/9/6
+ **/
+public class EchoStreamObserver<T, R> implements StreamObserver<T> {
+
+    private final Function<T, R> echoFunc;
+    private final StreamObserver<R> responseObserver;
+
+    public EchoStreamObserver(Function<T, R> echoFunc, StreamObserver<R> responseObserver) {
+        this.echoFunc = echoFunc;
+        this.responseObserver = responseObserver;
+    }
+
+    @Override
+    public void onNext(T data) {
+        responseObserver.onNext(echoFunc.apply(data));
+    }
+
+    @Override
+    public void onError(Throwable throwable) {
+        throwable.printStackTrace();
+        responseObserver.onError(new IllegalStateException("Stream err"));
+    }
+
+    @Override
+    public void onCompleted() {
+        responseObserver.onCompleted();
+    }
+}
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/GenericConsumer.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/GenericConsumer.java
new file mode 100644
index 0000000..3364ce6
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/GenericConsumer.java
@@ -0,0 +1,57 @@
+/*
+ *  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.sample.tri;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.rpc.service.GenericService;
+
+public class GenericConsumer {
+    private final GenericService generic;
+
+    GenericConsumer() {
+        ReferenceConfig<GenericService> ref = new ReferenceConfig<>();
+        ref.setInterface("org.apache.dubbo.sample.basic.IGreeter2");
+        ref.setCheck(false);
+        ref.setTimeout(30000);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setGeneric("true");
+        ref.setLazy(true);
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .reference(ref)
+                .start();
+        this.generic = ref.get();
+    }
+
+    public static void main(String[] args) {
+        final GenericConsumer consumer = new GenericConsumer();
+        System.out.println("dubbo triple generic consumer started");
+        consumer.sayHelloUnary();
+    }
+
+    public void sayHelloUnary() {
+        System.out.println(generic.$invoke("sayHello", new String[]{String.class.getName()}, new Object[]{"unary"}));
+    }
+
+
+}
\ No newline at end of file
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IGreeter.java
similarity index 77%
rename from dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter.java
rename to dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IGreeter.java
index c8d215e..2e3c74a 100644
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/IGreeter.java
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IGreeter.java
@@ -15,17 +15,17 @@
  *  limitations under the License.
  */
 
-package com.apache.dubbo.sample.basic;
+package org.apache.dubbo.sample.tri;
 
+import org.apache.dubbo.common.stream.StreamObserver;
 import org.apache.dubbo.hello.HelloReply;
 import org.apache.dubbo.hello.HelloRequest;
 
 public interface IGreeter {
-    /**
-     * <pre>
-     *  Sends a greeting
-     * </pre>
-     */
+
     HelloReply sayHello(HelloRequest request);
 
+    StreamObserver<HelloRequest> sayHelloStream(StreamObserver<HelloReply> replyStream);
+
+    void sayHelloServerStream(HelloRequest request, StreamObserver<HelloReply> replyStream);
 }
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IGreeter1Impl.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IGreeter1Impl.java
new file mode 100644
index 0000000..b94e61e
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IGreeter1Impl.java
@@ -0,0 +1,73 @@
+/*
+ *  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.sample.tri;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+import org.apache.dubbo.hello.HelloReply;
+import org.apache.dubbo.hello.HelloRequest;
+import org.apache.dubbo.rpc.RpcContext;
+
+public class IGreeter1Impl implements IGreeter {
+    @Override
+    public HelloReply sayHello(HelloRequest request) {
+
+        return HelloReply.newBuilder()
+                .setMessage(request.getName())
+                .build();
+    }
+
+    public HelloReply sayHelloException(HelloRequest request) {
+        RpcContext.getServerContext().setAttachment("str", "str")
+                .setAttachment("integer", 1)
+                .setAttachment("raw", new byte[]{1, 2, 3, 4});
+        throw new RuntimeException("Biz Exception");
+    }
+
+    @Override
+    public StreamObserver<HelloRequest> sayHelloStream(StreamObserver<HelloReply> replyStream) {
+        return new StreamObserver<HelloRequest>() {
+            @Override
+            public void onNext(HelloRequest data) {
+                replyStream.onNext(HelloReply.newBuilder()
+                        .setMessage(data.getName())
+                        .build());
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                throwable.printStackTrace();
+                replyStream.onError(new IllegalStateException("Stream err"));
+            }
+
+            @Override
+            public void onCompleted() {
+                replyStream.onCompleted();
+            }
+        };
+    }
+
+    @Override
+    public void sayHelloServerStream(HelloRequest request, StreamObserver<HelloReply> replyStream) {
+        for (int i = 0; i < 10; i++) {
+            replyStream.onNext(HelloReply.newBuilder()
+                    .setMessage(request.getName())
+                    .build());
+        }
+        replyStream.onCompleted();
+    }
+}
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IGreeter2Impl.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IGreeter2Impl.java
new file mode 100644
index 0000000..b10d689
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IGreeter2Impl.java
@@ -0,0 +1,73 @@
+/*
+ *  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.sample.tri;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+import org.apache.dubbo.rpc.RpcContext;
+
+public class IGreeter2Impl implements IWrapperGreeter {
+
+    @Override
+    public String sayHello(String request) {
+        return "hello," + request;
+    }
+
+    @Override
+    public void sayHelloResponseVoid(String request) {
+        System.out.println("call void response");
+    }
+
+    @Override
+    public String sayHelloRequestVoid() {
+        System.out.println("call void request");
+        return "hello!";
+    }
+
+    @Override
+    public String sayHelloException(String request) {
+        throw new RuntimeException("Biz exception");
+    }
+
+    @Override
+    public String sayHelloWithAttachment(String request) {
+        System.out.println(RpcContext.getServerAttachment().getObjectAttachments());
+        RpcContext.getServerContext().setAttachment("str", "str")
+                .setAttachment("integer", 1)
+                .setAttachment("raw", new byte[]{1, 2, 3, 4});
+        return "hello," + request;
+    }
+
+    @Override
+    public StreamObserver<String> sayHelloStream(StreamObserver<String> response) {
+        return new EchoStreamObserver<>(str -> "hello," + str, response);
+    }
+
+    @Override
+    public StreamObserver<String> sayHelloStreamError(StreamObserver<String> response) {
+        response.onError(new Throwable("ServerStream error"));
+        return new EchoStreamObserver<>(str -> "hello," + str, response);
+    }
+
+    @Override
+    public void sayHelloServerStream(String request, StreamObserver<String> response) {
+        for (int i = 0; i < 10; i++) {
+            response.onNext("hello," + request);
+        }
+        response.onCompleted();
+    }
+}
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IWrapperGreeter.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IWrapperGreeter.java
new file mode 100644
index 0000000..e49d593
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/IWrapperGreeter.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.sample.tri;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+
+public interface IWrapperGreeter {
+
+    String sayHello(String request);
+
+    void sayHelloResponseVoid(String request);
+
+    String sayHelloRequestVoid();
+
+    String sayHelloException(String request);
+
+    String sayHelloWithAttachment(String request);
+
+    StreamObserver<String> sayHelloStream(StreamObserver<String> response);
+
+    StreamObserver<String> sayHelloStreamError(StreamObserver<String> response);
+
+    void sayHelloServerStream(String request, StreamObserver<String> response);
+}
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/StdoutStreamObserver.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/StdoutStreamObserver.java
new file mode 100644
index 0000000..f8bd41d
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/StdoutStreamObserver.java
@@ -0,0 +1,33 @@
+package org.apache.dubbo.sample.tri;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+
+/**
+ * @author earthchen
+ * @date 2021/9/6
+ **/
+public class StdoutStreamObserver<T> implements StreamObserver<T>, io.grpc.stub.StreamObserver<T> {
+
+
+    private final String name;
+
+    public StdoutStreamObserver(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void onNext(T data) {
+        System.out.println("[" + name + "] stream reply:" + data);
+    }
+
+    @Override
+    public void onError(Throwable throwable) {
+        System.err.println("[" + name + "] Error:");
+        throwable.printStackTrace();
+    }
+
+    @Override
+    public void onCompleted() {
+        System.out.println("[" + name + "] stream done");
+    }
+}
\ No newline at end of file
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/TriSampleConstants.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/TriSampleConstants.java
new file mode 100644
index 0000000..b62314c
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/TriSampleConstants.java
@@ -0,0 +1,44 @@
+/*
+ *  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.sample.tri;
+
+
+import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_ALL;
+import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INSTANCE;
+import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INTERFACE;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;
+
+public class TriSampleConstants {
+
+    // macos 11 later the 50051 is occupied by system (pid=1!!!)
+    public static final int SERVER_PORT = 50052;
+
+    public static final int DEFAULT_DUBBO_PORT = 20880;
+
+    public static final String ZK_ADDRESS = "zookeeper://127.0.0.1:2181";
+
+    public static final String ZK_ADDRESS_MODE_INSTANCE = "zookeeper://127.0.0.1:2181?" + REGISTER_MODE_KEY + "=" + DEFAULT_REGISTER_MODE_INSTANCE;
+
+    public static final String ZK_ADDRESS_MODE_INTERFACE = "zookeeper://127.0.0.1:2181?" + REGISTER_MODE_KEY + "=" + DEFAULT_REGISTER_MODE_INTERFACE;
+
+    public static final String ZK_ADDRESS_MODE_ALL = "zookeeper://127.0.0.1:2181?" + REGISTER_MODE_KEY + "=" + DEFAULT_REGISTER_MODE_ALL;
+
+    public static final String HOST = "127.0.0.1";
+
+    public static final String DEFAULT_ADDRESS = "tri://" + HOST + ":" + SERVER_PORT;
+}
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothConsumer.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothConsumer.java
new file mode 100644
index 0000000..d60769d
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothConsumer.java
@@ -0,0 +1,72 @@
+/*
+ *  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.sample.tri.migration;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.IWrapperGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+
+class ApiMigrationBothConsumer {
+    private final IWrapperGreeter dubboDelegate;
+    private final IWrapperGreeter triDelegate;
+
+    public ApiMigrationBothConsumer() {
+        ReferenceConfig<IWrapperGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(IWrapperGreeter.class);
+        ref.setCheck(false);
+        ref.setTimeout(3000);
+        ref.setProtocol(CommonConstants.DUBBO_PROTOCOL);
+        ref.setLazy(true);
+
+        ReferenceConfig<IWrapperGreeter> ref2 = new ReferenceConfig<>();
+        ref2.setInterface(IWrapperGreeter.class);
+        ref2.setCheck(false);
+        ref2.setTimeout(3000);
+        ref2.setProtocol(CommonConstants.TRIPLE);
+        ref2.setLazy(true);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-migration-dubbo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .reference(ref)
+                .reference(ref2)
+                .start();
+        this.dubboDelegate = ref.get();
+        this.triDelegate = ref2.get();
+    }
+
+    public static void main(String[] args) {
+        final ApiMigrationBothConsumer consumer = new ApiMigrationBothConsumer();
+        System.out.println("demo-migration-both-consumer started");
+        consumer.sayHelloUnary(CommonConstants.DUBBO_PROTOCOL);
+        consumer.sayTriHelloUnary(CommonConstants.TRIPLE);
+    }
+
+    public void sayHelloUnary(String protocol) {
+        System.out.println(dubboDelegate.sayHello("unary" + "--" + protocol));
+    }
+
+    public void sayTriHelloUnary(String protocol) {
+        System.out.println(triDelegate.sayHello("unary" + "--" + protocol));
+    }
+
+}
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiWrapperProvider.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothProvider.java
similarity index 67%
copy from dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiWrapperProvider.java
copy to dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothProvider.java
index ce979fb..4bf7d86 100644
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiWrapperProvider.java
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothProvider.java
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package com.apache.dubbo.sample.basic;
+package org.apache.dubbo.sample.tri.migration;
 
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.config.ApplicationConfig;
@@ -23,17 +23,23 @@
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.IGreeter2Impl;
+import org.apache.dubbo.sample.tri.IWrapperGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
 
-public class ApiWrapperProvider {
+class ApiMigrationBothProvider {
+
     public static void main(String[] args) {
-        ServiceConfig<IGreeter2> service = new ServiceConfig<>();
-        service.setInterface(IGreeter2.class);
+
+        ServiceConfig<IWrapperGreeter> service = new ServiceConfig<>();
+        service.setInterface(IWrapperGreeter.class);
         service.setRef(new IGreeter2Impl());
 
         DubboBootstrap bootstrap = DubboBootstrap.getInstance();
-        bootstrap.application(new ApplicationConfig("demo-provider"))
-                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
-                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051))
+        bootstrap.application(new ApplicationConfig("demo-migration-both-provider"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .protocol(new ProtocolConfig(CommonConstants.DUBBO, TriSampleConstants.DEFAULT_DUBBO_PORT))
+                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, TriSampleConstants.SERVER_PORT))
                 .service(service)
                 .start()
                 .await();
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboConsumer.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboConsumer.java
new file mode 100644
index 0000000..b3542dc
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboConsumer.java
@@ -0,0 +1,57 @@
+/*
+ *  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.sample.tri.migration;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.IWrapperGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+
+class ApiMigrationDubboConsumer {
+    private final IWrapperGreeter delegate;
+
+    public ApiMigrationDubboConsumer() {
+        ReferenceConfig<IWrapperGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(IWrapperGreeter.class);
+        ref.setCheck(false);
+        ref.setTimeout(3000);
+        ref.setProtocol(CommonConstants.DUBBO_PROTOCOL);
+        ref.setLazy(true);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-migration-dubbo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .reference(ref)
+                .start();
+        this.delegate = ref.get();
+    }
+
+    public static void main(String[] args) {
+        final ApiMigrationDubboConsumer consumer = new ApiMigrationDubboConsumer();
+        System.out.println("demo-migration-dubbo-consumer dubbo started");
+        consumer.sayHelloUnary(CommonConstants.DUBBO_PROTOCOL);
+    }
+
+    public void sayHelloUnary(String protocol) {
+        System.out.println(delegate.sayHello("unary" + "--" + protocol));
+    }
+
+}
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiProvider.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboProvider.java
similarity index 64%
copy from dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiProvider.java
copy to dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboProvider.java
index df90b39..c35bbf5 100644
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiProvider.java
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboProvider.java
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package com.apache.dubbo.sample.basic;
+package org.apache.dubbo.sample.tri.migration;
 
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.config.ApplicationConfig;
@@ -23,18 +23,22 @@
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.IGreeter2Impl;
+import org.apache.dubbo.sample.tri.IWrapperGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
 
-public class ApiProvider {
+class ApiMigrationDubboProvider {
+
     public static void main(String[] args) {
-        ServiceConfig<IGreeter> service = new ServiceConfig<>();
-        service.setInterface(IGreeter.class);
-        service.setRef(new IGreeter1Impl());
+        ServiceConfig<IWrapperGreeter> service2 = new ServiceConfig<>();
+        service2.setInterface(IWrapperGreeter.class);
+        service2.setRef(new IGreeter2Impl());
 
         DubboBootstrap bootstrap = DubboBootstrap.getInstance();
-        bootstrap.application(new ApplicationConfig("demo-provider"))
-                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
-                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051))
-                .service(service)
+        bootstrap.application(new ApplicationConfig("demo-migration-dubbo-provider"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .protocol(new ProtocolConfig(CommonConstants.DUBBO, TriSampleConstants.DEFAULT_DUBBO_PORT))
+                .service(service2)
                 .start()
                 .await();
 
diff --git a/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriConsumer.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriConsumer.java
new file mode 100644
index 0000000..42327d6
--- /dev/null
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriConsumer.java
@@ -0,0 +1,57 @@
+/*
+ *  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.sample.tri.migration;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.IWrapperGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+
+class ApiMigrationTriConsumer {
+    private final IWrapperGreeter triDelegate;
+
+    public ApiMigrationTriConsumer() {
+        ReferenceConfig<IWrapperGreeter> ref2 = new ReferenceConfig<>();
+        ref2.setInterface(IWrapperGreeter.class);
+        ref2.setCheck(false);
+        ref2.setTimeout(3000);
+        ref2.setProtocol(CommonConstants.TRIPLE);
+        ref2.setLazy(true);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-migration-tri-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .reference(ref2)
+                .start();
+        this.triDelegate = ref2.get();
+    }
+
+    public static void main(String[] args) {
+        final ApiMigrationTriConsumer consumer = new ApiMigrationTriConsumer();
+        System.out.println("demo-migration-both-consumer started");
+        consumer.sayTriHelloUnary(CommonConstants.TRIPLE);
+    }
+
+    public void sayTriHelloUnary(String protocol) {
+        System.out.println(triDelegate.sayHello("unary" + "--" + protocol));
+    }
+
+}
diff --git a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiProvider.java b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriProvider.java
similarity index 67%
copy from dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiProvider.java
copy to dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriProvider.java
index df90b39..a4ae481 100644
--- a/dubbo-samples-triple/src/main/java/com/apache/dubbo/sample/basic/ApiProvider.java
+++ b/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriProvider.java
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package com.apache.dubbo.sample.basic;
+package org.apache.dubbo.sample.tri.migration;
 
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.config.ApplicationConfig;
@@ -23,18 +23,23 @@
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.IGreeter2Impl;
+import org.apache.dubbo.sample.tri.IWrapperGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
 
-public class ApiProvider {
+class ApiMigrationTriProvider {
+
     public static void main(String[] args) {
-        ServiceConfig<IGreeter> service = new ServiceConfig<>();
-        service.setInterface(IGreeter.class);
-        service.setRef(new IGreeter1Impl());
+
+        ServiceConfig<IWrapperGreeter> service2 = new ServiceConfig<>();
+        service2.setInterface(IWrapperGreeter.class);
+        service2.setRef(new IGreeter2Impl());
 
         DubboBootstrap bootstrap = DubboBootstrap.getInstance();
-        bootstrap.application(new ApplicationConfig("demo-provider"))
-                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
-                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051))
-                .service(service)
+        bootstrap.application(new ApplicationConfig("demo-migration-tri-provider"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, TriSampleConstants.SERVER_PORT))
+                .service(service2)
                 .start()
                 .await();
 
diff --git a/dubbo-samples-triple/src/main/resources/META-INF/services/org.apache.dubbo.rpc.cluster.filter.ClusterFilter b/dubbo-samples-triple/src/main/resources/META-INF/services/org.apache.dubbo.rpc.cluster.filter.ClusterFilter
new file mode 100644
index 0000000..140074e
--- /dev/null
+++ b/dubbo-samples-triple/src/main/resources/META-INF/services/org.apache.dubbo.rpc.cluster.filter.ClusterFilter
@@ -0,0 +1 @@
+com.apache.dubbo.sample.tri.BizErrorCodeClientFilter
\ No newline at end of file
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/BasePbConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/BasePbConsumerTest.java
new file mode 100644
index 0000000..dee40b6
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/BasePbConsumerTest.java
@@ -0,0 +1,105 @@
+package org.apache.dubbo.sample.tri;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author earthchen
+ * @date 2021/9/9
+ **/
+public abstract class BasePbConsumerTest {
+
+    protected static PbGreeter delegate;
+
+    protected static PbGreeterManual delegateManual;
+
+    @Test
+    public void serverStream() throws InterruptedException {
+        int n = 10;
+        CountDownLatch latch = new CountDownLatch(n);
+        final GreeterRequest request = GreeterRequest.newBuilder()
+                .setName("request")
+                .build();
+        delegate.greetServerStream(request, new StdoutStreamObserver<GreeterReply>("sayGreeterServerStream") {
+            @Override
+            public void onNext(GreeterReply data) {
+                super.onNext(data);
+                latch.countDown();
+            }
+        });
+        Assert.assertTrue(latch.await(3, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void stream() throws InterruptedException {
+        int n = 10;
+        CountDownLatch latch = new CountDownLatch(n);
+        final GreeterRequest request = GreeterRequest.newBuilder()
+                .setName("stream request")
+                .build();
+        final StreamObserver<GreeterRequest> requestObserver = delegate.greetStream(new StdoutStreamObserver<GreeterReply>("sayGreeterStream") {
+            @Override
+            public void onNext(GreeterReply data) {
+                super.onNext(data);
+                latch.countDown();
+            }
+        });
+        for (int i = 0; i < n; i++) {
+            requestObserver.onNext(request);
+        }
+        requestObserver.onCompleted();
+        Assert.assertTrue(latch.await(3, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void unaryGreeter() {
+        final GreeterReply reply = delegate.greet(GreeterRequest.newBuilder()
+                .setName("name")
+                .build());
+        Assert.assertNotNull(reply);
+    }
+
+
+    @Test(expected = RpcException.class)
+    @Ignore
+    public void clientSendLargeSizeHeader() {
+        StringBuilder sb = new StringBuilder("a");
+        for (int j = 0; j < 15; j++) {
+            sb.append(sb);
+        }
+        sb.setLength(8191);
+        RpcContext.getClientAttachment().setObjectAttachment("large-size-meta", sb.toString());
+        delegate.greet(GreeterRequest.newBuilder().setName("meta").build());
+        RpcContext.getClientAttachment().clearAttachments();
+    }
+
+    @Test
+    public void attachmentTest() {
+        final String key = "user-attachment";
+        final String value = "attachment-value";
+        RpcContext.removeClientAttachment();
+        RpcContext.getClientAttachment().setAttachment(key, value);
+        delegate.greetWithAttachment(GreeterRequest.newBuilder().setName("meta").build());
+        final String returned = (String) RpcContext.getServiceContext().getObjectAttachment(key);
+        Assert.assertEquals(value, returned);
+    }
+
+    @Test
+    public void methodNotFound() {
+        try {
+            delegateManual.methodNonExist(GreeterRequest.newBuilder().setName("meta").build());
+            TimeUnit.SECONDS.sleep(1);
+        } catch (RpcException | InterruptedException e) {
+            Assert.assertTrue(e.getMessage().contains("not found"));
+        }
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/BaseTriWrapConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/BaseTriWrapConsumerTest.java
new file mode 100644
index 0000000..ceebf5e
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/BaseTriWrapConsumerTest.java
@@ -0,0 +1,121 @@
+package org.apache.dubbo.sample.tri;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class BaseTriWrapConsumerTest {
+
+    protected static WrapGreeter delegate;
+
+    @Test
+    public void sayHelloUnaryRequestVoid() {
+        Assert.assertEquals("hello!void", delegate.sayHelloRequestVoid());
+    }
+
+    @Test
+    public void sayHelloUnaryResponseVoid() {
+        delegate.sayHelloResponseVoid("void");
+    }
+
+    @Test
+    public void sayHelloUnary() {
+        Assert.assertEquals("hello,unary", delegate.sayHello("unary"));
+    }
+
+    @Test(expected = RpcException.class)
+    public void sayHelloException() {
+        delegate.sayHelloException("exception");
+    }
+
+    @Test
+    public void sayHelloServerStream() throws InterruptedException {
+        int n = 10;
+        CountDownLatch latch = new CountDownLatch(n);
+        delegate.sayHelloServerStream("server stream", new StdoutStreamObserver<String>("sayHelloServerStream") {
+            @Override
+            public void onNext(String data) {
+                super.onNext(data);
+                latch.countDown();
+            }
+        });
+        Assert.assertTrue(latch.await(3, TimeUnit.SECONDS));
+
+
+        delegate.sayHelloServerStream("server stream", new StreamObserver<String>() {
+            @Override
+            public void onNext(String data) {
+                System.out.println(data);
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                throwable.printStackTrace();
+            }
+
+            @Override
+            public void onCompleted() {
+                System.out.println("onCompleted");
+            }
+        });
+
+
+        StreamObserver<String> request = delegate.sayHelloStream(new StreamObserver<String>() {
+            @Override
+            public void onNext(String data) {
+                System.out.println(data);
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                throwable.printStackTrace();
+            }
+
+            @Override
+            public void onCompleted() {
+                System.out.println("onCompleted");
+            }
+        });
+        for (int i = 0; i < n; i++) {
+            request.onNext("stream request" + i);
+        }
+        request.onCompleted();
+
+
+    }
+
+    @Test
+    public void sayHelloStream() throws InterruptedException {
+        int n = 10;
+        CountDownLatch latch = new CountDownLatch(n);
+        final StreamObserver<String> request = delegate.sayHelloStream(new StdoutStreamObserver<String>("sayHelloStream") {
+            @Override
+            public void onNext(String data) {
+                super.onNext(data);
+                latch.countDown();
+            }
+        });
+        for (int i = 0; i < n; i++) {
+            request.onNext("stream request");
+        }
+        request.onCompleted();
+        Assert.assertTrue(latch.await(3, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void sayHelloLong() {
+        int power = 25;
+        for (int i = 0; i < power; i++) {
+            final int len = (1 << i);
+            final String response = delegate.sayHelloLong(len);
+            System.out.println("Response len:" + response.length());
+            Assert.assertEquals(len, response.length());
+        }
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/GrpcInterOPTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/GrpcInterOPTest.java
new file mode 100644
index 0000000..639cf8d
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/GrpcInterOPTest.java
@@ -0,0 +1,7 @@
+package org.apache.dubbo.sample.tri;
+
+/**
+ * See <a href="https://grpc.github.io/grpc/cpp/md_doc_http2-interop-test-descriptions.html">https://grpc.github.io/grpc/cpp/md_doc_http2-interop-test-descriptions.html</a>
+ */
+public class GrpcInterOPTest {
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriGenericTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriGenericTest.java
new file mode 100644
index 0000000..a9632af
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriGenericTest.java
@@ -0,0 +1,68 @@
+package org.apache.dubbo.sample.tri;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.service.GenericService;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TriGenericTest {
+    private static GenericService generic;
+
+    @BeforeClass
+    public static void init() {
+        ReferenceConfig<GenericService> ref = new ReferenceConfig<>();
+        ref.setInterface("org.apache.dubbo.sample.tri.service.WrapGreeter");
+        ref.setCheck(false);
+        ref.setTimeout(30000);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setGeneric("true");
+        ref.setLazy(true);
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .reference(ref)
+                .start();
+        generic = ref.get();
+    }
+
+    @Test
+    public void sayHelloUnaryRequestVoid() {
+        Assert.assertNotNull(generic.$invoke("sayHelloRequestVoid", new String[0], new Object[0]));
+    }
+
+    @Test
+    public void sayHelloUnaryResponseVoid() {
+        generic.$invoke("sayHelloResponseVoid", new String[]{String.class.getName()},
+                new Object[]{"requestVoid"});
+    }
+
+    @Test
+    public void sayHelloUnary() {
+        Assert.assertEquals("hello,unary", generic.$invoke("sayHello",
+                new String[]{String.class.getName()}, new Object[]{"unary"}));
+    }
+
+    @Test(expected = RpcException.class)
+    public void sayHelloException() {
+        generic.$invoke("sayHelloException", new String[]{String.class.getName()}, new Object[]{"exception"});
+    }
+
+    @Test(expected = RpcException.class)
+    public void notFoundMethod() {
+        generic.$invoke("sayHelloNotExist", new String[]{String.class.getName()}, new Object[]{"unary long"});
+    }
+
+    @Test
+    public void sayHelloLong() {
+        int len = 2 << 24;
+        final String resp = (String) generic.$invoke("sayHelloLong", new String[]{int.class.getName()}, new Object[]{len});
+        Assert.assertEquals(len, resp.length());
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriPbConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriPbConsumerTest.java
new file mode 100644
index 0000000..c274649
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriPbConsumerTest.java
@@ -0,0 +1,40 @@
+package org.apache.dubbo.sample.tri;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+
+import org.junit.BeforeClass;
+
+public class TriPbConsumerTest extends BasePbConsumerTest {
+
+    @BeforeClass
+    public static void init() {
+        ReferenceConfig<PbGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(PbGreeter.class);
+        ref.setCheck(false);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setLazy(true);
+        ref.setTimeout(10000);
+
+        ReferenceConfig<PbGreeterManual> ref2 = new ReferenceConfig<>();
+        ref2.setInterface(PbGreeterManual.class);
+        ref2.setCheck(false);
+        ref2.setProtocol(CommonConstants.TRIPLE);
+        ref2.setLazy(true);
+        ref2.setTimeout(10000);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .reference(ref)
+                .reference(ref2)
+                .start();
+
+        delegate = ref.get();
+        delegateManual = ref2.get();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriProvider.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriProvider.java
new file mode 100644
index 0000000..542ca97
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriProvider.java
@@ -0,0 +1,41 @@
+package org.apache.dubbo.sample.tri;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.service.impl.PbGreeterImpl;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+import org.apache.dubbo.sample.tri.service.impl.WrapGreeterImpl;
+
+
+public class TriProvider {
+
+    public static void main(String[] args) {
+        ServiceConfig<PbGreeter> pbService = new ServiceConfig<>();
+        pbService.setInterface(PbGreeter.class);
+        PbGreeterImpl greeterImpl = new PbGreeterImpl();
+        pbService.setRef(greeterImpl);
+
+        ServiceConfig<PbGreeterManual> pbManualService = new ServiceConfig<>();
+        pbManualService.setInterface(PbGreeterManual.class);
+        pbManualService.setRef(new PbGreeterImpl());
+
+        ServiceConfig<WrapGreeter> wrapService = new ServiceConfig<>();
+        wrapService.setInterface(WrapGreeter.class);
+        wrapService.setRef(new WrapGreeterImpl());
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-provider"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, TriSampleConstants.SERVER_PORT))
+                .service(pbService)
+                .service(pbManualService)
+                .service(wrapService)
+                .start()
+                .await();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriWrapConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriWrapConsumerTest.java
new file mode 100644
index 0000000..3d91db9
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/TriWrapConsumerTest.java
@@ -0,0 +1,144 @@
+package org.apache.dubbo.sample.tri;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.stream.StreamObserver;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class TriWrapConsumerTest {
+
+    private static WrapGreeter delegate;
+
+    @BeforeClass
+    public static void initStub() {
+        ReferenceConfig<WrapGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(WrapGreeter.class);
+        ref.setCheck(false);
+        ref.setTimeout(3000);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setLazy(true);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS))
+                .reference(ref)
+                .start();
+        delegate = ref.get();
+    }
+
+    @Test
+    public void sayHelloUnaryRequestVoid() {
+        Assert.assertEquals("hello!void", delegate.sayHelloRequestVoid());
+    }
+
+    @Test
+    public void sayHelloUnaryResponseVoid() {
+        delegate.sayHelloResponseVoid("void");
+    }
+
+    @Test
+    public void sayHelloUnary() {
+        Assert.assertEquals("hello,unary", delegate.sayHello("unary"));
+    }
+
+    @Test(expected = RpcException.class)
+    public void sayHelloException() {
+        delegate.sayHelloException("exception");
+    }
+
+    @Test
+    public void sayHelloServerStream() throws InterruptedException {
+        int n = 10;
+        CountDownLatch latch = new CountDownLatch(n);
+        delegate.sayHelloServerStream("server stream", new StdoutStreamObserver<String>("sayHelloServerStream") {
+            @Override
+            public void onNext(String data) {
+                super.onNext(data);
+                latch.countDown();
+            }
+        });
+        Assert.assertTrue(latch.await(3, TimeUnit.SECONDS));
+
+
+        delegate.sayHelloServerStream("server stream", new StreamObserver<String>() {
+            @Override
+            public void onNext(String data) {
+                System.out.println(data);
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                throwable.printStackTrace();
+            }
+
+            @Override
+            public void onCompleted() {
+                System.out.println("onCompleted");
+            }
+        });
+
+
+        StreamObserver<String> request = delegate.sayHelloStream(new StreamObserver<String>() {
+            @Override
+            public void onNext(String data) {
+                System.out.println(data);
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                throwable.printStackTrace();
+            }
+
+            @Override
+            public void onCompleted() {
+                System.out.println("onCompleted");
+            }
+        });
+        for (int i = 0; i < n; i++) {
+            request.onNext("stream request" + i);
+        }
+        request.onCompleted();
+
+
+    }
+
+    @Test
+    public void sayHelloStream() throws InterruptedException {
+        int n = 10;
+        CountDownLatch latch = new CountDownLatch(n);
+        final StreamObserver<String> request = delegate.sayHelloStream(new StdoutStreamObserver<String>("sayHelloStream") {
+            @Override
+            public void onNext(String data) {
+                super.onNext(data);
+                latch.countDown();
+            }
+        });
+        for (int i = 0; i < n; i++) {
+            request.onNext("stream request");
+        }
+        request.onCompleted();
+        Assert.assertTrue(latch.await(3, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void sayHelloLong() {
+        int power = 25;
+        for (int i = 0; i < power; i++) {
+            final int len = (1 << i);
+            final String response = delegate.sayHelloLong(len);
+            System.out.println("Response len:" + response.length());
+            Assert.assertEquals(len, response.length());
+        }
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/all/TriAllProvider.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/all/TriAllProvider.java
new file mode 100644
index 0000000..3368479
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/all/TriAllProvider.java
@@ -0,0 +1,44 @@
+package org.apache.dubbo.sample.tri.all;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.PbGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+import org.apache.dubbo.sample.tri.service.impl.PbGreeterImpl;
+import org.apache.dubbo.sample.tri.service.impl.WrapGreeterImpl;
+
+
+public class TriAllProvider {
+
+    public static void main(String[] args) {
+        ServiceConfig<PbGreeter> pbService = new ServiceConfig<>();
+        pbService.setInterface(PbGreeter.class);
+        PbGreeterImpl greeterImpl = new PbGreeterImpl();
+        pbService.setRef(greeterImpl);
+
+        ServiceConfig<PbGreeterManual> pbManualService = new ServiceConfig<>();
+        pbManualService.setInterface(PbGreeterManual.class);
+        pbManualService.setRef(new PbGreeterImpl());
+
+        ServiceConfig<WrapGreeter> wrapService = new ServiceConfig<>();
+        wrapService.setInterface(WrapGreeter.class);
+        wrapService.setRef(new WrapGreeterImpl());
+
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-provider"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS_MODE_ALL))
+                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, TriSampleConstants.SERVER_PORT))
+                .service(pbService)
+                .service(pbManualService)
+                .service(wrapService)
+                .start()
+                .await();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/application/TriAppPbConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/application/TriAppPbConsumerTest.java
new file mode 100644
index 0000000..2ff92b3
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/application/TriAppPbConsumerTest.java
@@ -0,0 +1,42 @@
+package org.apache.dubbo.sample.tri.application;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.BasePbConsumerTest;
+import org.apache.dubbo.sample.tri.PbGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+
+import org.junit.BeforeClass;
+
+public class TriAppPbConsumerTest extends BasePbConsumerTest {
+
+    @BeforeClass
+    public static void init() {
+        ReferenceConfig<PbGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(PbGreeter.class);
+        ref.setCheck(false);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setLazy(true);
+        ref.setTimeout(10000);
+
+        ReferenceConfig<PbGreeterManual> ref2 = new ReferenceConfig<>();
+        ref2.setInterface(PbGreeterManual.class);
+        ref2.setCheck(false);
+        ref2.setProtocol(CommonConstants.TRIPLE);
+        ref2.setLazy(true);
+        ref2.setTimeout(10000);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS_MODE_INSTANCE))
+                .reference(ref)
+                .reference(ref2)
+                .start();
+        delegate = ref.get();
+        delegateManual = ref2.get();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/application/TriAppProvider.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/application/TriAppProvider.java
new file mode 100644
index 0000000..214a6f8
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/application/TriAppProvider.java
@@ -0,0 +1,43 @@
+package org.apache.dubbo.sample.tri.application;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.PbGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+import org.apache.dubbo.sample.tri.service.impl.PbGreeterImpl;
+import org.apache.dubbo.sample.tri.service.impl.WrapGreeterImpl;
+
+
+public class TriAppProvider {
+    public static void main(String[] args) {
+        ServiceConfig<PbGreeter> pbService = new ServiceConfig<>();
+        pbService.setInterface(PbGreeter.class);
+        PbGreeterImpl greeterImpl = new PbGreeterImpl();
+        pbService.setRef(greeterImpl);
+
+        ServiceConfig<PbGreeterManual> pbManualService = new ServiceConfig<>();
+        pbManualService.setInterface(PbGreeterManual.class);
+        pbManualService.setRef(new PbGreeterImpl());
+
+        ServiceConfig<WrapGreeter> wrapService = new ServiceConfig<>();
+        wrapService.setInterface(WrapGreeter.class);
+        wrapService.setRef(new WrapGreeterImpl());
+
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-provider"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS_MODE_INSTANCE))
+                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, TriSampleConstants.SERVER_PORT))
+                .service(pbService)
+                .service(pbManualService)
+                .service(wrapService)
+                .start()
+                .await();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/application/TriAppWrapConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/application/TriAppWrapConsumerTest.java
new file mode 100644
index 0000000..200fb12
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/application/TriAppWrapConsumerTest.java
@@ -0,0 +1,33 @@
+package org.apache.dubbo.sample.tri.application;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.BaseTriWrapConsumerTest;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+
+import org.junit.BeforeClass;
+
+public class TriAppWrapConsumerTest extends BaseTriWrapConsumerTest {
+
+    @BeforeClass
+    public static void initStub() {
+        ReferenceConfig<WrapGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(WrapGreeter.class);
+        ref.setCheck(false);
+        ref.setTimeout(3000);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setLazy(true);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS_MODE_INSTANCE))
+                .reference(ref)
+                .start();
+        delegate = ref.get();
+    }
+
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/direct/TriDirectPbConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/direct/TriDirectPbConsumerTest.java
new file mode 100644
index 0000000..c0b0aef
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/direct/TriDirectPbConsumerTest.java
@@ -0,0 +1,42 @@
+package org.apache.dubbo.sample.tri.direct;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.BasePbConsumerTest;
+import org.apache.dubbo.sample.tri.PbGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+
+import org.junit.BeforeClass;
+
+public class TriDirectPbConsumerTest extends BasePbConsumerTest {
+
+    @BeforeClass
+    public static void init() {
+        ReferenceConfig<PbGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(PbGreeter.class);
+        ref.setCheck(false);
+        ref.setUrl(TriSampleConstants.DEFAULT_ADDRESS);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setLazy(true);
+        ref.setTimeout(10000);
+
+        ReferenceConfig<PbGreeterManual> ref2 = new ReferenceConfig<>();
+        ref2.setInterface(PbGreeterManual.class);
+        ref2.setCheck(false);
+        ref2.setUrl(TriSampleConstants.DEFAULT_ADDRESS);
+        ref2.setProtocol(CommonConstants.TRIPLE);
+        ref2.setLazy(true);
+        ref2.setTimeout(10000);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .reference(ref)
+                .reference(ref2)
+                .start();
+        delegate = ref.get();
+        delegateManual = ref2.get();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/direct/TriDirectWrapConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/direct/TriDirectWrapConsumerTest.java
new file mode 100644
index 0000000..c47afb5
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/direct/TriDirectWrapConsumerTest.java
@@ -0,0 +1,32 @@
+package org.apache.dubbo.sample.tri.direct;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.BaseTriWrapConsumerTest;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+
+import org.junit.BeforeClass;
+
+public class TriDirectWrapConsumerTest extends BaseTriWrapConsumerTest {
+
+    @BeforeClass
+    public static void initStub() {
+        ReferenceConfig<WrapGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(WrapGreeter.class);
+        ref.setCheck(false);
+        ref.setTimeout(3000);
+        ref.setUrl(TriSampleConstants.DEFAULT_ADDRESS);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setLazy(true);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .reference(ref)
+                .start();
+        delegate = ref.get();
+    }
+
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/grpc/GrpcConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/grpc/GrpcConsumerTest.java
new file mode 100644
index 0000000..f58dab3
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/grpc/GrpcConsumerTest.java
@@ -0,0 +1,106 @@
+package org.apache.dubbo.sample.tri.grpc;
+
+import org.apache.dubbo.sample.tri.GreeterReply;
+import org.apache.dubbo.sample.tri.GreeterRequest;
+import org.apache.dubbo.sample.tri.PbGreeterGrpc;
+import org.apache.dubbo.sample.tri.StdoutStreamObserver;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.Metadata;
+import io.grpc.stub.MetadataUtils;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class GrpcConsumerTest {
+    private static PbGreeterGrpc.PbGreeterStub stub;
+    private static PbGreeterGrpc.PbGreeterBlockingStub blockingStub;
+
+    @BeforeClass
+    public static void init() {
+        final ManagedChannel channel = ManagedChannelBuilder.forAddress(TriSampleConstants.HOST, TriSampleConstants.SERVER_PORT)
+                .usePlaintext()
+                .build();
+        stub = PbGreeterGrpc.newStub(channel);
+        blockingStub = PbGreeterGrpc.newBlockingStub(channel);
+    }
+
+    @Test
+    public void clientSendLargeSizeHeader() throws InterruptedException {
+        final Metadata.Key<String> key = Metadata.Key.of("large_size", Metadata.ASCII_STRING_MARSHALLER);
+        StringBuilder sb = new StringBuilder("a");
+        for (int j = 0; j < 15; j++) {
+            sb.append(sb);
+        }
+        Metadata meta = new Metadata();
+        meta.put(key, sb.toString());
+        final PbGreeterGrpc.PbGreeterStub curStub = MetadataUtils.attachHeaders(GrpcConsumerTest.stub, meta);
+        curStub.greet(GreeterRequest.newBuilder().setName("metadata").build(), new StdoutStreamObserver<>("meta"));
+        TimeUnit.SECONDS.sleep(1);
+    }
+
+    @Test
+    public void serverStream() throws InterruptedException {
+        int n = 10;
+        CountDownLatch latch = new CountDownLatch(n);
+        final GreeterRequest request = GreeterRequest.newBuilder()
+                .setName("request")
+                .build();
+        stub.greetServerStream(request, new StdoutStreamObserver<GreeterReply>("grpc sayGreeterServerStream") {
+            @Override
+            public void onNext(GreeterReply data) {
+                super.onNext(data);
+                latch.countDown();
+            }
+        });
+        Assert.assertTrue(latch.await(3, TimeUnit.SECONDS));
+    }
+
+
+    @Test
+    public void stream() throws InterruptedException {
+        int n = 10;
+        CountDownLatch latch = new CountDownLatch(n);
+        final GreeterRequest request = GreeterRequest.newBuilder()
+                .setName("stream request")
+                .build();
+        final io.grpc.stub.StreamObserver<GreeterRequest> requestObserver = stub.greetStream(new StdoutStreamObserver<GreeterReply>("sayGreeterStream") {
+            @Override
+            public void onNext(GreeterReply data) {
+                super.onNext(data);
+                latch.countDown();
+            }
+        });
+        for (int i = 0; i < n; i++) {
+            requestObserver.onNext(request);
+        }
+        requestObserver.onCompleted();
+        Assert.assertTrue(latch.await(3, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void unaryGreeter() {
+        final GreeterReply reply = blockingStub.greet(GreeterRequest.newBuilder()
+                .setName("name")
+                .build());
+        Assert.assertNotNull(reply);
+    }
+
+
+    @Test
+    public void attachmentTest() {
+        final Metadata.Key<String> key = Metadata.Key.of("large_size", Metadata.ASCII_STRING_MARSHALLER);
+        Metadata meta = new Metadata();
+        meta.put(key, "test");
+        final PbGreeterGrpc.PbGreeterBlockingStub curStub = MetadataUtils.attachHeaders(GrpcConsumerTest.blockingStub, meta);
+        GreeterReply reply = curStub.greetWithAttachment(GreeterRequest.newBuilder().setName("meta").build());
+        Assert.assertEquals("hello,meta", reply.getMessage());
+    }
+
+}
+
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/grpc/GrpcProvider.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/grpc/GrpcProvider.java
new file mode 100644
index 0000000..6287b4e
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/grpc/GrpcProvider.java
@@ -0,0 +1,68 @@
+package org.apache.dubbo.sample.tri.grpc;
+
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.impl.GrpcPbGreeterImpl;
+import org.apache.dubbo.sample.tri.service.impl.PbGreeterImpl;
+
+import io.grpc.ForwardingServerCall;
+import io.grpc.Metadata;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.grpc.ServerCall;
+import io.grpc.ServerCallHandler;
+import io.grpc.ServerInterceptor;
+import io.grpc.ServerInterceptors;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+public class GrpcProvider {
+    public static void main(String[] args) throws IOException, InterruptedException {
+        final Server server = ServerBuilder.forPort(TriSampleConstants.SERVER_PORT)
+                .addService(ServerInterceptors.intercept(new GrpcPbGreeterImpl(new PbGreeterImpl()), new ServerInterceptor() {
+                    @Override
+                    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall,
+                                                                                 Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
+                        return serverCallHandler.startCall(new ForwardingServerCall.SimpleForwardingServerCall(serverCall) {
+                            @Override
+                            public void sendHeaders(Metadata headers) {
+                                final String key = "user-attachment";
+                                final Metadata.Key<String> metaKey = Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER);
+                                if (metadata.containsKey(metaKey)) {
+                                    headers.put(metaKey, metadata.get(metaKey));
+                                }
+                                super.sendHeaders(headers);
+                            }
+                        }, metadata);
+                    }
+
+                    ;
+                }))
+                .build();
+        server.start();
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override
+            public void run() {
+                // Start graceful shutdown
+                server.shutdown();
+                try {
+                    // Wait for RPCs to complete processing
+                    if (!server.awaitTermination(30, TimeUnit.SECONDS)) {
+                        // That was plenty of time. Let's cancel the remaining RPCs
+                        server.shutdownNow();
+                        // shutdownNow isn't instantaneous, so give a bit of time to clean resources up
+                        // gracefully. Normally this will be well under a second.
+                        server.awaitTermination(5, TimeUnit.SECONDS);
+                    }
+                } catch (InterruptedException ex) {
+                    server.shutdownNow();
+                }
+            }
+        });
+        // This would normally be tied to the service's dependencies. For example, if HostnameGreeter
+        // used a Channel to contact a required service, then when 'channel.getState() ==
+        // TRANSIENT_FAILURE' we'd want to set NOT_SERVING. But HostnameGreeter has no dependencies, so
+        // hard-coding SERVING is appropriate.
+        server.awaitTermination();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/helper/GrpcStreamObserverAdapter.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/helper/GrpcStreamObserverAdapter.java
new file mode 100644
index 0000000..91cbef4
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/helper/GrpcStreamObserverAdapter.java
@@ -0,0 +1,28 @@
+package org.apache.dubbo.sample.tri.helper;
+
+
+import io.grpc.stub.StreamObserver;
+
+public class GrpcStreamObserverAdapter<T> implements StreamObserver<T> {
+
+    private final org.apache.dubbo.common.stream.StreamObserver<T> delegate;
+
+    public GrpcStreamObserverAdapter(org.apache.dubbo.common.stream.StreamObserver<T> delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public void onNext(T data) {
+        delegate.onNext(data);
+    }
+
+    @Override
+    public void onError(Throwable throwable) {
+        delegate.onError(throwable);
+    }
+
+    @Override
+    public void onCompleted() {
+        delegate.onCompleted();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/helper/StreamObserverAdapter.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/helper/StreamObserverAdapter.java
new file mode 100644
index 0000000..614f213
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/helper/StreamObserverAdapter.java
@@ -0,0 +1,26 @@
+package org.apache.dubbo.sample.tri.helper;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+
+public class StreamObserverAdapter<T> implements StreamObserver<T> {
+    private final io.grpc.stub.StreamObserver<T> delegate;
+
+    public StreamObserverAdapter(io.grpc.stub.StreamObserver<T> delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public void onNext(T data) {
+        delegate.onNext(data);
+    }
+
+    @Override
+    public void onError(Throwable throwable) {
+        delegate.onError(throwable);
+    }
+
+    @Override
+    public void onCompleted() {
+        delegate.onCompleted();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/inter/TriInterfacePbConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/inter/TriInterfacePbConsumerTest.java
new file mode 100644
index 0000000..aea094d
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/inter/TriInterfacePbConsumerTest.java
@@ -0,0 +1,42 @@
+package org.apache.dubbo.sample.tri.inter;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.BasePbConsumerTest;
+import org.apache.dubbo.sample.tri.PbGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+
+import org.junit.BeforeClass;
+
+public class TriInterfacePbConsumerTest extends BasePbConsumerTest {
+
+    @BeforeClass
+    public static void init() {
+        ReferenceConfig<PbGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(PbGreeter.class);
+        ref.setCheck(false);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setLazy(true);
+        ref.setTimeout(10000);
+
+        ReferenceConfig<PbGreeterManual> ref2 = new ReferenceConfig<>();
+        ref2.setInterface(PbGreeterManual.class);
+        ref2.setCheck(false);
+        ref2.setProtocol(CommonConstants.TRIPLE);
+        ref2.setLazy(true);
+        ref2.setTimeout(10000);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS_MODE_INTERFACE))
+                .reference(ref)
+                .reference(ref2)
+                .start();
+        delegate = ref.get();
+        delegateManual = ref2.get();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/inter/TriInterfaceProvider.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/inter/TriInterfaceProvider.java
new file mode 100644
index 0000000..c01e98e
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/inter/TriInterfaceProvider.java
@@ -0,0 +1,44 @@
+package org.apache.dubbo.sample.tri.inter;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.PbGreeter;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+import org.apache.dubbo.sample.tri.service.impl.PbGreeterImpl;
+import org.apache.dubbo.sample.tri.service.impl.WrapGreeterImpl;
+
+
+public class TriInterfaceProvider {
+
+    public static void main(String[] args) {
+        ServiceConfig<PbGreeter> pbService = new ServiceConfig<>();
+        pbService.setInterface(PbGreeter.class);
+        PbGreeterImpl greeterImpl = new PbGreeterImpl();
+        pbService.setRef(greeterImpl);
+
+        ServiceConfig<PbGreeterManual> pbManualService = new ServiceConfig<>();
+        pbManualService.setInterface(PbGreeterManual.class);
+        pbManualService.setRef(new PbGreeterImpl());
+
+        ServiceConfig<WrapGreeter> wrapService = new ServiceConfig<>();
+        wrapService.setInterface(WrapGreeter.class);
+        wrapService.setRef(new WrapGreeterImpl());
+
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-provider"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS_MODE_INTERFACE))
+                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, TriSampleConstants.SERVER_PORT))
+                .service(pbService)
+                .service(pbManualService)
+                .service(wrapService)
+                .start()
+                .await();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/inter/TriInterfaceWrapConsumerTest.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/inter/TriInterfaceWrapConsumerTest.java
new file mode 100644
index 0000000..e69b372
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/inter/TriInterfaceWrapConsumerTest.java
@@ -0,0 +1,34 @@
+package org.apache.dubbo.sample.tri.inter;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.sample.tri.BaseTriWrapConsumerTest;
+import org.apache.dubbo.sample.tri.TriSampleConstants;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+
+import org.junit.BeforeClass;
+
+public class TriInterfaceWrapConsumerTest extends BaseTriWrapConsumerTest {
+
+    @BeforeClass
+    public static void initStub() {
+        ReferenceConfig<WrapGreeter> ref = new ReferenceConfig<>();
+        ref.setInterface(WrapGreeter.class);
+        ref.setCheck(false);
+        ref.setTimeout(3000);
+        ref.setUrl(TriSampleConstants.DEFAULT_ADDRESS);
+        ref.setProtocol(CommonConstants.TRIPLE);
+        ref.setLazy(true);
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
+        bootstrap.application(new ApplicationConfig("demo-consumer"))
+                .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS_MODE_INTERFACE))
+                .reference(ref)
+                .start();
+        delegate = ref.get();
+    }
+
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/PbGreeterManual.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/PbGreeterManual.java
new file mode 100644
index 0000000..8627e13
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/PbGreeterManual.java
@@ -0,0 +1,21 @@
+package org.apache.dubbo.sample.tri.service;
+
+import org.apache.dubbo.sample.tri.GreeterReply;
+import org.apache.dubbo.sample.tri.GreeterRequest;
+
+/**
+ * this is by manual and other by dubbo compiler
+ */
+public interface PbGreeterManual {
+//    GreeterReply greetWithAttachment(GreeterRequest request);
+//
+//    GreeterReply greet(GreeterRequest request);
+
+    GreeterReply methodNonExist(GreeterRequest request);
+//
+//    GreeterReply greetException(GreeterRequest request);
+//
+//    StreamObserver<GreeterRequest> greetStream(StreamObserver<GreeterReply> replyStream);
+//
+//    void greetServerStream(GreeterRequest request, StreamObserver<GreeterReply> replyStream);
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/WrapGreeter.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/WrapGreeter.java
new file mode 100644
index 0000000..2e182dd
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/WrapGreeter.java
@@ -0,0 +1,43 @@
+package org.apache.dubbo.sample.tri.service;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+
+public interface WrapGreeter {
+    /**
+     * <pre>
+     *  Sends a greeting
+     * </pre>
+     */
+    String sayHelloLong(int len);
+
+    /**
+     * unray
+     */
+    String sayHello(String request);
+
+    /**
+     * unray
+     */
+    void sayHelloResponseVoid(String request);
+
+    /**
+     * unray
+     */
+    String sayHelloRequestVoid();
+
+    String sayHelloException(String request);
+
+    String sayHelloWithAttachment(String request);
+
+    /**
+     * bi stream
+     */
+    StreamObserver<String> sayHelloStream(StreamObserver<String> response);
+
+    StreamObserver<String> sayHelloStreamError(StreamObserver<String> response);
+
+    /**
+     * server stream
+     */
+    void sayHelloServerStream(String request, StreamObserver<String> response);
+}
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/impl/GrpcPbGreeterImpl.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/impl/GrpcPbGreeterImpl.java
new file mode 100644
index 0000000..e0736e8
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/impl/GrpcPbGreeterImpl.java
@@ -0,0 +1,62 @@
+package org.apache.dubbo.sample.tri.service.impl;
+
+import org.apache.dubbo.sample.tri.GreeterReply;
+import org.apache.dubbo.sample.tri.GreeterRequest;
+import org.apache.dubbo.sample.tri.helper.GrpcStreamObserverAdapter;
+import org.apache.dubbo.sample.tri.PbGreeter;
+import org.apache.dubbo.sample.tri.PbGreeterGrpc;
+import org.apache.dubbo.sample.tri.helper.StreamObserverAdapter;
+
+import io.grpc.stub.StreamObserver;
+
+public class GrpcPbGreeterImpl extends PbGreeterGrpc.PbGreeterImplBase {
+
+    private final PbGreeter delegate;
+
+    public GrpcPbGreeterImpl(PbGreeter delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public void greet(GreeterRequest request, StreamObserver<GreeterReply> responseObserver) {
+        try {
+            final GreeterReply response = delegate.greet(request);
+            responseObserver.onNext(response);
+            responseObserver.onCompleted();
+        } catch (Throwable t) {
+            responseObserver.onError(t);
+        }
+    }
+
+    @Override
+    public void greetException(GreeterRequest request, StreamObserver<GreeterReply> responseObserver) {
+        try {
+            final GreeterReply response = delegate.greetException(request);
+            responseObserver.onNext(response);
+            responseObserver.onCompleted();
+        } catch (Throwable t) {
+            responseObserver.onError(t);
+        }
+    }
+
+    @Override
+    public StreamObserver<GreeterRequest> greetStream(StreamObserver<GreeterReply> responseObserver) {
+        return new GrpcStreamObserverAdapter<>(delegate.greetStream(new StreamObserverAdapter<>(responseObserver)));
+    }
+
+    @Override
+    public void greetWithAttachment(GreeterRequest request, StreamObserver<GreeterReply> responseObserver) {
+        try {
+            final GreeterReply response = delegate.greetWithAttachment(request);
+            responseObserver.onNext(response);
+            responseObserver.onCompleted();
+        } catch (Throwable t) {
+            responseObserver.onError(t);
+        }
+    }
+
+    @Override
+    public void greetServerStream(GreeterRequest request, StreamObserver<GreeterReply> responseObserver) {
+        delegate.greetServerStream(request, new StreamObserverAdapter<>(responseObserver));
+    }
+}
\ No newline at end of file
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/impl/PbGreeterImpl.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/impl/PbGreeterImpl.java
new file mode 100644
index 0000000..b9becff
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/impl/PbGreeterImpl.java
@@ -0,0 +1,72 @@
+package org.apache.dubbo.sample.tri.service.impl;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.sample.tri.GreeterReply;
+import org.apache.dubbo.sample.tri.GreeterRequest;
+import org.apache.dubbo.sample.tri.PbGreeter;
+import org.apache.dubbo.sample.tri.service.PbGreeterManual;
+
+public class PbGreeterImpl implements PbGreeter, PbGreeterManual {
+
+    @Override
+    public GreeterReply greetWithAttachment(GreeterRequest request) {
+        final String key = "user-attachment";
+        final String value = RpcContext.getServerAttachment().getAttachment(key);
+        RpcContext.getServerContext().setObjectAttachment(key, value);
+        return GreeterReply.newBuilder().setMessage("hello," + request.getName()).build();
+    }
+
+    @Override
+    public GreeterReply greet(GreeterRequest request) {
+
+        return GreeterReply.newBuilder()
+                .setMessage(request.getName())
+                .build();
+    }
+
+    @Override
+    public GreeterReply methodNonExist(GreeterRequest request) {
+        throw new RuntimeException("not found");
+    }
+
+    public GreeterReply greetException(GreeterRequest request) {
+        RpcContext.getServerContext().setAttachment("str", "str")
+                .setAttachment("integer", 1)
+                .setAttachment("raw", new byte[]{1, 2, 3, 4});
+        throw new RuntimeException("Biz Exception");
+    }
+
+    @Override
+    public StreamObserver<GreeterRequest> greetStream(StreamObserver<GreeterReply> replyStream) {
+        return new StreamObserver<GreeterRequest>() {
+            @Override
+            public void onNext(GreeterRequest data) {
+                replyStream.onNext(GreeterReply.newBuilder()
+                        .setMessage(data.getName())
+                        .build());
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                throwable.printStackTrace();
+                replyStream.onError(new IllegalStateException("Stream err"));
+            }
+
+            @Override
+            public void onCompleted() {
+                replyStream.onCompleted();
+            }
+        };
+    }
+
+    @Override
+    public void greetServerStream(GreeterRequest request, StreamObserver<GreeterReply> replyStream) {
+        for (int i = 0; i < 10; i++) {
+            replyStream.onNext(GreeterReply.newBuilder()
+                    .setMessage(request.getName() + "--" + i)
+                    .build());
+        }
+        replyStream.onCompleted();
+    }
+}
\ No newline at end of file
diff --git a/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/impl/WrapGreeterImpl.java b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/impl/WrapGreeterImpl.java
new file mode 100644
index 0000000..d8f118e
--- /dev/null
+++ b/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/service/impl/WrapGreeterImpl.java
@@ -0,0 +1,85 @@
+package org.apache.dubbo.sample.tri.service.impl;
+
+import org.apache.dubbo.common.stream.StreamObserver;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.sample.tri.EchoStreamObserver;
+import org.apache.dubbo.sample.tri.service.WrapGreeter;
+
+public class WrapGreeterImpl implements WrapGreeter {
+    @Override
+    public String sayHelloLong(int len) {
+        StringBuilder respBuilder = new StringBuilder();
+        if (len > 0) {
+            respBuilder.append("a");
+        }
+        for (; respBuilder.length() < len; respBuilder.append(respBuilder)) {
+            respBuilder.append(respBuilder);
+        }
+        return respBuilder.substring(0, len);
+    }
+
+    @Override
+    public String sayHello(String request) {
+        return "hello," + request;
+    }
+
+    @Override
+    public void sayHelloResponseVoid(String request) {
+        System.out.println("call void response");
+    }
+
+    @Override
+    public String sayHelloRequestVoid() {
+        return "hello!void";
+    }
+
+    @Override
+    public String sayHelloException(String request) {
+        throw new IllegalStateException("Biz exception");
+    }
+
+    @Override
+    public String sayHelloWithAttachment(String request) {
+        System.out.println(RpcContext.getServerAttachment().getObjectAttachments());
+        RpcContext.getServerContext().setAttachment("str", "str")
+                .setAttachment("integer", 1)
+                .setAttachment("raw", new byte[]{1, 2, 3, 4});
+        return "hello," + request;
+    }
+
+    @Override
+    public StreamObserver<String> sayHelloStream(StreamObserver<String> response) {
+        return new StreamObserver<String>() {
+            @Override
+            public void onNext(String data) {
+                System.out.println(data);
+                response.onNext("hello,"+data);
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                throwable.printStackTrace();
+            }
+
+            @Override
+            public void onCompleted() {
+                System.out.println("onCompleted");
+                response.onCompleted();
+            }
+        };
+    }
+
+    @Override
+    public StreamObserver<String> sayHelloStreamError(StreamObserver<String> response) {
+        response.onError(new Throwable("ServerStream error"));
+        return new EchoStreamObserver<>(str -> "hello," + str, response);
+    }
+
+    @Override
+    public void sayHelloServerStream(String request, StreamObserver<String> response) {
+        for (int i = 0; i < 10; i++) {
+            response.onNext("hello," + request);
+        }
+        response.onCompleted();
+    }
+}
diff --git a/dubbo-samples-triple/src/test/proto/empty.proto b/dubbo-samples-triple/src/test/proto/empty.proto
new file mode 100644
index 0000000..01305a6
--- /dev/null
+++ b/dubbo-samples-triple/src/test/proto/empty.proto
@@ -0,0 +1,30 @@
+
+// Copyright 2015 gRPC authors.
+//
+// Licensed 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.
+
+
+syntax = "proto3";
+
+package grpc.testing;
+
+// see https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/empty.proto
+// An empty message that you can re-use to avoid defining duplicated empty
+// messages in your project. A typical example is to use it as argument or the
+// return value of a service API. For instance:
+//
+//   service Foo {
+//     rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
+//   };
+//
+message Empty {}
\ No newline at end of file
diff --git a/dubbo-samples-triple/src/test/proto/messages.proto b/dubbo-samples-triple/src/test/proto/messages.proto
new file mode 100644
index 0000000..cd9b7e0
--- /dev/null
+++ b/dubbo-samples-triple/src/test/proto/messages.proto
@@ -0,0 +1,270 @@
+
+// Copyright 2015-2016 gRPC authors.
+//
+// Licensed 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.
+
+// Message definitions to be used by integration test service definitions.
+
+syntax = "proto3";
+
+package grpc.testing;
+
+// TODO(dgq): Go back to using well-known types once
+// https://github.com/grpc/grpc/issues/6980 has been fixed.
+// import "google/protobuf/wrappers.proto";
+message BoolValue {
+  // The bool value.
+  bool value = 1;
+}
+
+// The type of payload that should be returned.
+enum PayloadType {
+  // Compressable text format.
+  COMPRESSABLE = 0;
+}
+
+// A block of data, to simply increase gRPC message size.
+message Payload {
+  // The type of data in body.
+  PayloadType type = 1;
+  // Primary contents of payload.
+  bytes body = 2;
+}
+
+// A protobuf representation for grpc status. This is used by test
+// clients to specify a status that the server should attempt to return.
+message EchoStatus {
+  int32 code = 1;
+  string message = 2;
+}
+
+// The type of route that a client took to reach a server w.r.t. gRPCLB.
+// The server must fill in "fallback" if it detects that the RPC reached
+// the server via the "gRPCLB fallback" path, and "backend" if it detects
+// that the RPC reached the server via "gRPCLB backend" path (i.e. if it got
+// the address of this server from the gRPCLB server BalanceLoad RPC). Exactly
+// how this detection is done is context and server dependent.
+enum GrpclbRouteType {
+  // Server didn't detect the route that a client took to reach it.
+  GRPCLB_ROUTE_TYPE_UNKNOWN = 0;
+  // Indicates that a client reached a server via gRPCLB fallback.
+  GRPCLB_ROUTE_TYPE_FALLBACK = 1;
+  // Indicates that a client reached a server as a gRPCLB-given backend.
+  GRPCLB_ROUTE_TYPE_BACKEND = 2;
+}
+
+// Unary request.
+message SimpleRequest {
+  // Desired payload type in the response from the server.
+  // If response_type is RANDOM, server randomly chooses one from other formats.
+  PayloadType response_type = 1;
+
+  // Desired payload size in the response from the server.
+  int32 response_size = 2;
+
+  // Optional input payload sent along with the request.
+  Payload payload = 3;
+
+  // Whether SimpleResponse should include username.
+  bool fill_username = 4;
+
+  // Whether SimpleResponse should include OAuth scope.
+  bool fill_oauth_scope = 5;
+
+  // Whether to request the server to compress the response. This field is
+  // "nullable" in order to interoperate seamlessly with clients not able to
+  // implement the full compression tests by introspecting the call to verify
+  // the response's compression status.
+  BoolValue response_compressed = 6;
+
+  // Whether server should return a given status
+  EchoStatus response_status = 7;
+
+  // Whether the server should expect this request to be compressed.
+  BoolValue expect_compressed = 8;
+
+  // Whether SimpleResponse should include server_id.
+  bool fill_server_id = 9;
+
+  // Whether SimpleResponse should include grpclb_route_type.
+  bool fill_grpclb_route_type = 10;
+}
+
+// Unary response, as configured by the request.
+message SimpleResponse {
+  // Payload to increase message size.
+  Payload payload = 1;
+  // The user the request came from, for verifying authentication was
+  // successful when the client expected it.
+  string username = 2;
+  // OAuth scope.
+  string oauth_scope = 3;
+
+  // Server ID. This must be unique among different server instances,
+  // but the same across all RPC's made to a particular server instance.
+  string server_id = 4;
+  // gRPCLB Path.
+  GrpclbRouteType grpclb_route_type = 5;
+
+  // Server hostname.
+  string hostname = 6;
+}
+
+// Client-streaming request.
+message StreamingInputCallRequest {
+  // Optional input payload sent along with the request.
+  Payload payload = 1;
+
+  // Whether the server should expect this request to be compressed. This field
+  // is "nullable" in order to interoperate seamlessly with servers not able to
+  // implement the full compression tests by introspecting the call to verify
+  // the request's compression status.
+  BoolValue expect_compressed = 2;
+
+  // Not expecting any payload from the response.
+}
+
+// Client-streaming response.
+message StreamingInputCallResponse {
+  // Aggregated size of payloads received from the client.
+  int32 aggregated_payload_size = 1;
+}
+
+// Configuration for a particular response.
+message ResponseParameters {
+  // Desired payload sizes in responses from the server.
+  int32 size = 1;
+
+  // Desired interval between consecutive responses in the response stream in
+  // microseconds.
+  int32 interval_us = 2;
+
+  // Whether to request the server to compress the response. This field is
+  // "nullable" in order to interoperate seamlessly with clients not able to
+  // implement the full compression tests by introspecting the call to verify
+  // the response's compression status.
+  BoolValue compressed = 3;
+}
+
+// Server-streaming request.
+message StreamingOutputCallRequest {
+  // Desired payload type in the response from the server.
+  // If response_type is RANDOM, the payload from each response in the stream
+  // might be of different types. This is to simulate a mixed type of payload
+  // stream.
+  PayloadType response_type = 1;
+
+  // Configuration for each expected response message.
+  repeated ResponseParameters response_parameters = 2;
+
+  // Optional input payload sent along with the request.
+  Payload payload = 3;
+
+  // Whether server should return a given status
+  EchoStatus response_status = 7;
+}
+
+// Server-streaming response, as configured by the request and parameters.
+message StreamingOutputCallResponse {
+  // Payload to increase response size.
+  Payload payload = 1;
+}
+
+// For reconnect interop test only.
+// Client tells server what reconnection parameters it used.
+message ReconnectParams {
+  int32 max_reconnect_backoff_ms = 1;
+}
+
+// For reconnect interop test only.
+// Server tells client whether its reconnects are following the spec and the
+// reconnect backoffs it saw.
+message ReconnectInfo {
+  bool passed = 1;
+  repeated int32 backoff_ms = 2;
+}
+
+message LoadBalancerStatsRequest {
+  // Request stats for the next num_rpcs sent by client.
+  int32 num_rpcs = 1;
+  // If num_rpcs have not completed within timeout_sec, return partial results.
+  int32 timeout_sec = 2;
+}
+
+message LoadBalancerStatsResponse {
+  message RpcsByPeer {
+    // The number of completed RPCs for each peer.
+    map<string, int32> rpcs_by_peer = 1;
+  }
+  // The number of completed RPCs for each peer.
+  map<string, int32> rpcs_by_peer = 1;
+  // The number of RPCs that failed to record a remote peer.
+  int32 num_failures = 2;
+  map<string, RpcsByPeer> rpcs_by_method = 3;
+}
+
+// Request for retrieving a test client's accumulated stats.
+message LoadBalancerAccumulatedStatsRequest {}
+
+// Accumulated stats for RPCs sent by a test client.
+message LoadBalancerAccumulatedStatsResponse {
+  // The total number of RPCs have ever issued for each type.
+  // Deprecated: use stats_per_method.rpcs_started instead.
+  map<string, int32> num_rpcs_started_by_method = 1 [deprecated = true];
+  // The total number of RPCs have ever completed successfully for each type.
+  // Deprecated: use stats_per_method.result instead.
+  map<string, int32> num_rpcs_succeeded_by_method = 2 [deprecated = true];
+  // The total number of RPCs have ever failed for each type.
+  // Deprecated: use stats_per_method.result instead.
+  map<string, int32> num_rpcs_failed_by_method = 3 [deprecated = true];
+
+  message MethodStats {
+    // The number of RPCs that were started for this method.
+    int32 rpcs_started = 1;
+
+    // The number of RPCs that completed with each status for this method.  The
+    // key is the integral value of a google.rpc.Code; the value is the count.
+    map<int32, int32> result = 2;
+  }
+
+  // Per-method RPC statistics.  The key is the RpcType in string form; e.g.
+  // 'EMPTY_CALL' or 'UNARY_CALL'
+  map<string, MethodStats> stats_per_method = 4;
+}
+
+// Configurations for a test client.
+message ClientConfigureRequest {
+  // Type of RPCs to send.
+  enum RpcType {
+    EMPTY_CALL = 0;
+    UNARY_CALL = 1;
+  }
+
+  // Metadata to be attached for the given type of RPCs.
+  message Metadata {
+    RpcType type = 1;
+    string key = 2;
+    string value = 3;
+  }
+
+  // The types of RPCs the client sends.
+  repeated RpcType types = 1;
+  // The collection of custom metadata to be attached to RPCs sent by the client.
+  repeated Metadata metadata = 2;
+  // The deadline to use, in seconds, for all RPCs.  If unset or zero, the
+  // client will use the default from the command-line.
+  int32 timeout_sec = 3;
+}
+
+// Response for updating a test client's configuration.
+message ClientConfigureResponse {}
\ No newline at end of file
diff --git a/dubbo-samples-triple/src/test/proto/prototest.proto b/dubbo-samples-triple/src/test/proto/prototest.proto
new file mode 100644
index 0000000..e3e83dd
--- /dev/null
+++ b/dubbo-samples-triple/src/test/proto/prototest.proto
@@ -0,0 +1,28 @@
+syntax = "proto3";
+
+option java_multiple_files = true;
+
+package org.apache.dubbo.sample.tri;
+
+
+// The request message containing the user's name.
+message GreeterRequest {
+  string name = 1;
+}
+
+// The response message containing the greetings
+message GreeterReply {
+  string message = 1;
+}
+
+service PbGreeter{
+  rpc greet(GreeterRequest) returns (GreeterReply);
+
+  rpc greetWithAttachment (GreeterRequest) returns (GreeterReply);
+
+  rpc greetException(GreeterRequest) returns (GreeterReply);
+
+  rpc greetStream(stream GreeterRequest) returns (stream GreeterReply);
+
+  rpc greetServerStream(GreeterRequest) returns (stream GreeterReply);
+}
diff --git a/dubbo-samples-triple/src/test/proto/test.proto b/dubbo-samples-triple/src/test/proto/test.proto
new file mode 100644
index 0000000..3fdf9c1
--- /dev/null
+++ b/dubbo-samples-triple/src/test/proto/test.proto
@@ -0,0 +1,104 @@
+
+// Copyright 2015-2016 gRPC authors.
+//
+// Licensed 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.
+
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+syntax = "proto3";
+
+option java_multiple_files = true;
+
+import "empty.proto";
+import "messages.proto";
+
+package grpc.testing;
+
+// See https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/test.proto
+// A simple service to test the various types of RPCs and experiment with
+// performance with various types of payload.
+service TestService {
+  // One empty request followed by one empty response.
+  rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
+
+  // One request followed by one response.
+  rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
+
+  // One request followed by one response. Response has cache control
+  // headers set such that a caching HTTP proxy (such as GFE) can
+  // satisfy subsequent requests.
+  rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse);
+
+  // One request followed by a sequence of responses (streamed download).
+  // The server returns the payload with client desired type and sizes.
+  rpc StreamingOutputCall(StreamingOutputCallRequest)
+      returns (stream StreamingOutputCallResponse);
+
+  // A sequence of requests followed by one response (streamed upload).
+  // The server returns the aggregated size of client payload as the result.
+  rpc StreamingInputCall(stream StreamingInputCallRequest)
+      returns (StreamingInputCallResponse);
+
+  // A sequence of requests with each request served by the server immediately.
+  // As one request could lead to multiple responses, this interface
+  // demonstrates the idea of full duplexing.
+  rpc FullDuplexCall(stream StreamingOutputCallRequest)
+      returns (stream StreamingOutputCallResponse);
+
+  // A sequence of requests followed by a sequence of responses.
+  // The server buffers all the client requests and then serves them in order. A
+  // stream of responses are returned to the client when the server starts with
+  // first request.
+  rpc HalfDuplexCall(stream StreamingOutputCallRequest)
+      returns (stream StreamingOutputCallResponse);
+
+  // The test server will not implement this method. It will be used
+  // to test the behavior when clients call unimplemented methods.
+  rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty);
+}
+
+// A simple service NOT implemented at servers so clients can test for
+// that case.
+service UnimplementedService {
+  // A call that no server should implement
+  rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty);
+}
+
+// A service used to control reconnect server.
+service ReconnectService {
+  rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty);
+  rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo);
+}
+
+// A service used to obtain stats for verifying LB behavior.
+service LoadBalancerStatsService {
+  // Gets the backend distribution for RPCs sent by a test client.
+  rpc GetClientStats(LoadBalancerStatsRequest)
+      returns (LoadBalancerStatsResponse) {}
+
+  // Gets the accumulated stats for RPCs sent by a test client.
+  rpc GetClientAccumulatedStats(LoadBalancerAccumulatedStatsRequest)
+      returns (LoadBalancerAccumulatedStatsResponse) {}
+}
+
+// A service to remotely control health status of an xDS test server.
+service XdsUpdateHealthService {
+  rpc SetServing(grpc.testing.Empty) returns (grpc.testing.Empty);
+  rpc SetNotServing(grpc.testing.Empty) returns (grpc.testing.Empty);
+}
+
+// A service to dynamically update the configuration of an xDS test client.
+service XdsUpdateClientConfigureService {
+  // Update the tes client's configuration.
+  rpc Configure(ClientConfigureRequest) returns (ClientConfigureResponse);
+}
\ No newline at end of file