Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

servlet: Implement gRPC server as a Servlet #8596

Merged
merged 133 commits into from
Jan 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
a0c92df
POC: Implement gRPC server as a Servlet
dapengzhang0 Jul 31, 2018
8719377
better-logging
dapengzhang0 Aug 12, 2018
46d00ec
get rid of public ServerImpl
dapengzhang0 Aug 13, 2018
4fa6271
rename files
dapengzhang0 Aug 14, 2018
e793c7c
fix serverListener NPE
dapengzhang0 Aug 14, 2018
393fcf6
fix onSendingBytes()
dapengzhang0 Aug 15, 2018
706a3c9
favor ConcurrentLinkedQueue for library
dapengzhang0 Aug 16, 2018
5e11674
refactor ServletAdapterImpl to ServletAdapter
dapengzhang0 Aug 17, 2018
1776917
not to use CDI for simplicity
dapengzhang0 Aug 17, 2018
bb3a720
add GrpcServlet(ServletServerBuilder serverBuilder)
dapengzhang0 Oct 15, 2018
4c7cd4f
add UndertowInteropTest and UndertowAbstractTest
dapengzhang0 Nov 2, 2018
af7f6a3
fix codecov
dapengzhang0 Nov 15, 2018
2fc04fc
minor enhancements
dapengzhang0 Nov 16, 2018
6fb4fc2
Merge branch 'master' of https://github.com/grpc/grpc-java into servl…
dapengzhang0 Jan 2, 2019
8b78b6d
update example gradle files
dapengzhang0 Jan 3, 2019
680872b
Merge branch 'master' of https://github.com/grpc/grpc-java into servl…
dapengzhang0 Jan 7, 2019
b3473df
Merge branch 'master' of https://github.com/grpc/grpc-java into servl…
dapengzhang0 Jun 13, 2019
3728866
revert core/src/test/java/io/grpc/internal/AbstractTransportTest.java
dapengzhang0 Jun 13, 2019
58fce63
ignore some transport tests
dapengzhang0 Jun 13, 2019
5b02064
cleanup GrpcServlet constructor
dapengzhang0 Jun 13, 2019
d59f81e
better way to get authority
dapengzhang0 Jun 13, 2019
5b7496e
comment SPSC
dapengzhang0 Jul 5, 2019
e98e4f8
attributes.toBuilder()
dapengzhang0 Jul 5, 2019
6aa26e4
move writeState and WriteListener
dapengzhang0 Jul 5, 2019
c3dfaba
Merge branch 'master' of https://github.com/grpc/grpc-java into servl…
dapengzhang0 Jul 8, 2019
44ea5f3
revert AbstractTransportTest reformat
dapengzhang0 Jul 8, 2019
ef5f879
temp
dapengzhang0 Jul 14, 2019
47e3e95
fix some of review comments
dapengzhang0 Jul 17, 2019
c5fc2bd
create util methods
dapengzhang0 Aug 7, 2019
63e8cb2
minor cleanup
dapengzhang0 Aug 7, 2019
986a885
Merge branch 'master' of https://github.com/grpc/grpc-java into servl…
dapengzhang0 Aug 11, 2019
3fd4ca8
factor out write path so that easy to replace with other implementation
dapengzhang0 Aug 12, 2019
09967c1
xds: gate xDS timeout with env variable (v1.33.x backport) (#7504) (#…
voidzcy Oct 13, 2020
7d8410f
Update README etc to reference 1.33.0
dapengzhang0 Oct 20, 2020
a53114b
Merge commit '38952b0b3' into servletasync
niloc132 Jan 14, 2021
ae0085f
Update servlet build to catch up to changes at around the 1.25 release
niloc132 Jan 14, 2021
9a02c82
Merge commit '2d592642a' into servletasync
niloc132 Jan 14, 2021
7977de6
Merge commit '04cf90a9a' into servletasync
niloc132 Jan 14, 2021
811fcbe
Update test to use the new conventions
niloc132 Jan 14, 2021
ccbfd8d
Merge commit 'df1b67869' into servletasync
niloc132 Jan 14, 2021
5d017a3
Merge commit '5c31dc6d7' into servletasync
niloc132 Jan 14, 2021
0180d29
Merge commit 'a86fc47c0' into servletasync
niloc132 Jan 15, 2021
7bb191c
Add explicit guava dependency
niloc132 Jan 15, 2021
59d9754
Merge commit '7047209ba' into servletasync
niloc132 Jan 15, 2021
1f4b0ca
Simple typos
niloc132 Sep 20, 2021
ccc5cd6
Merge commit 'v1.33.0^' into servletasync
niloc132 Sep 20, 2021
7d90af8
Merge commit '620d26667' into servletasync
niloc132 Sep 20, 2021
aea3351
Merge commit '73fe68eec' into servletasync
niloc132 Sep 20, 2021
70ca920
Merge commit '7d9ee8f05' into servletasync
niloc132 Sep 21, 2021
83d405e
Merge commit '828b03da2' into servletasync
niloc132 Sep 21, 2021
18d20d3
Merge commit 'd2160ea70' into servletasync
niloc132 Sep 21, 2021
f4c0c87
Merge commit 'dc74a31be' into servletasync
niloc132 Sep 21, 2021
b12370e
Merge commit '1e858921e' into servletasync
niloc132 Sep 21, 2021
a39be4c
tomcat
dapengzhang0 Aug 19, 2019
dea10c6
amend tomcat/jetty tests so they build after cherry-pick
niloc132 Sep 21, 2021
2154764
Relax jetty rate control
niloc132 Sep 23, 2021
bf5c225
Fix typo in log config, though apparently not used?
niloc132 Sep 23, 2021
a0b5852
Update tests to keep classpaths apart, fix/ignore failures
niloc132 Sep 27, 2021
512a2d3
Tomcat test cleanup, note about intermittent test
niloc132 Sep 27, 2021
4bed353
Typo in test class
niloc132 Sep 27, 2021
907f432
Restore another test setup piece, with fixed dependencies
niloc132 Sep 27, 2021
75f9b82
Update to java-library plugin, build javadoc
niloc132 Sep 27, 2021
cf3decb
Stubbed in servlet-jakarta project, rewrite commit with vers
niloc132 Sep 29, 2021
00b8f76
Simplify tests for javax.servlet
niloc132 Oct 12, 2021
35e0af2
Checkpoint before rewriting without this jakarta plugin...
niloc132 Oct 12, 2021
0c5664c
Working build+test on jakarta, with markers to delete jetty9 workaround
niloc132 Oct 13, 2021
8162d6e
Finish removing jakarta plugin
niloc132 Oct 13, 2021
8e25c4c
Merge remote-tracking branch 'upstream/master' into servletasync
niloc132 Oct 13, 2021
3bcd0af
Handle Java8 as well as Java11
niloc132 Oct 13, 2021
034771f
Disable another intermittent tomcat test
niloc132 Oct 13, 2021
da85cf8
Import cleanup
niloc132 Oct 13, 2021
f84a156
Upgrade various versions to latest, add some details about specific
niloc132 Oct 13, 2021
f7677f6
Example servlet readme
niloc132 Oct 13, 2021
dc2ddcf
Remove note that no longer applies
niloc132 Oct 13, 2021
cc9eb3f
Correct a different maven repo url
niloc132 Oct 13, 2021
67eb249
Rearrange test code, add jetty transport test
niloc132 Oct 26, 2021
c8eea3b
Update jakarta servlet tests too
niloc132 Oct 26, 2021
36c4e08
Merge remote-tracking branch 'upstream/master' into servletasync
niloc132 Oct 26, 2021
490abf2
Fix readme link error
niloc132 Oct 26, 2021
0db2bdf
Address JdkObsolete build errors
niloc132 Oct 26, 2021
6440b3b
Revert attempt to avoid StringBuffer, and add JdkObsolete suppress in…
niloc132 Nov 4, 2021
cc2297d
Fix build bug preventing jetty10 tests from running
niloc132 Nov 4, 2021
6197088
Merge branch 'master' into servlet-niloc132
dapengzhang0 Dec 22, 2021
9acba27
Make buildTransportServers() package private and VisibleForTesting
dapengzhang0 Dec 22, 2021
44fc657
fix bad import
dapengzhang0 Dec 22, 2021
6764b77
remove logging in test
dapengzhang0 Dec 22, 2021
7cce389
use org.apache.tomcat:annotations-api instead of javax.annotation
dapengzhang0 Dec 22, 2021
33639da
update RELEASING.md
dapengzhang0 Dec 22, 2021
822701e
remove unnecessary line
niloc132 Nov 29, 2021
f1a2ff3
Correctly publish jakarta artifact
niloc132 Dec 23, 2021
2a26e5e
Use empty() rather than making an empty byte[]
niloc132 Dec 23, 2021
a72bed1
Remove jetty 9 workaround
niloc132 Dec 23, 2021
a67519c
Update to latest servlet impls for tests
niloc132 Dec 23, 2021
0741d02
Configure tomcat to allow tests, remove skipped tests this fixes
niloc132 Dec 27, 2021
c88e1ce
retain test SourceSet for (future) normal unit test
dapengzhang0 Dec 29, 2021
4a55684
disable checkstyle in servlet-jakarta completely
dapengzhang0 Dec 29, 2021
d77973e
Revert "update RELEASING.md"
dapengzhang0 Dec 30, 2021
e632dde
make grpc-core an implementation dependency
dapengzhang0 Dec 30, 2021
c903d75
cleanup AsyncServletOutputStreamWriter
dapengzhang0 Dec 30, 2021
0bc4dcc
workaround tomcat outputStream.isReayd NPE after asyncCtx.complete
dapengzhang0 Jan 9, 2022
d73bad1
remove timeout rule for UndertowTransportTest
dapengzhang0 Jan 9, 2022
714e81b
Merge branch 'master' into servlet-niloc132
dapengzhang0 Jan 9, 2022
1962a0e
add jacoco coverage
dapengzhang0 Jan 9, 2022
022c66c
fix jacoco
dapengzhang0 Jan 9, 2022
bfef2a2
Change packages for jakarta servlet types
niloc132 Jan 19, 2022
bd3d791
Suppress java9+ warnings/errors from tomcat illegal reflective access
niloc132 Jan 19, 2022
533bd21
Merge branch 'master' into servlet-niloc132
dapengzhang0 Jan 22, 2022
6f7e626
bump grpc version in example
dapengzhang0 Jan 22, 2022
bc802ae
Un-ignore JettyInteropTest.gracefulShutdown
dapengzhang0 Jan 22, 2022
b1da336
Add servlet to grpc-all:javadoc
dapengzhang0 Jan 27, 2022
93f1c6f
fix jakarta build warning
dapengzhang0 Jan 27, 2022
0e64316
Concurrency correctness test for AsyncServletOutputStreamWriter
dapengzhang0 Jan 27, 2022
38c0585
enhance lincheck test
dapengzhang0 Feb 8, 2022
5cb764a
add test for builder scheduler and GrpcServlet constructor
dapengzhang0 Feb 16, 2022
986ee81
add test for builder scheduler and GrpcServlet constructor 2
dapengzhang0 Feb 16, 2022
95c350f
ignore flaky undertow test
dapengzhang0 Feb 16, 2022
7a90a53
add Test annotation
dapengzhang0 Feb 16, 2022
f8b9950
improve builder test
dapengzhang0 Feb 16, 2022
576d64e
response with error code for GET method
dapengzhang0 Feb 18, 2022
50020b3
fix executorPool and TIMER_SERVICE leak after servlet.destroy()
dapengzhang0 Feb 27, 2022
79dc180
Merge branch 'master' into servlet-niloc132
dapengzhang0 Mar 9, 2022
6d58c9b
bump grpc version in example
dapengzhang0 Mar 9, 2022
dda244d
Merge commit '78ccc81fd' into servletasync
niloc132 May 10, 2022
5829381
Merge branch 'master' of https://github.com/grpc/grpc-java into servl…
dapengzhang0 Jun 22, 2022
7ae71dc
bump grpc version in example
dapengzhang0 Jun 22, 2022
639084a
Use Gradle's version catalog
dapengzhang0 Jun 22, 2022
b13d505
regression while bumping to v1.47.0
dapengzhang0 Jun 22, 2022
5bbaea3
Merge commit '7bdca0c0e' into servletasync
niloc132 Jan 20, 2023
524bbe9
Merge commit 'e998955d1' into servletasync
niloc132 Jan 20, 2023
129628e
Merge commit 'a82ea0cb0' into servletasync
niloc132 Jan 20, 2023
4c68cfb
Merge commit 'e325dc911' into servletasync
niloc132 Jan 20, 2023
f26201a
Merge remote-tracking branch 'upstream/master' into servletasync
niloc132 Jan 20, 2023
7929461
Review feedback, version bump
niloc132 Jan 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ $ VERSION_FILES=(
examples/example-jwt-auth/pom.xml
examples/example-hostname/build.gradle
examples/example-hostname/pom.xml
examples/example-servlet/build.gradle
examples/example-tls/build.gradle
examples/example-tls/pom.xml
examples/example-xds/build.gradle
Expand Down
2 changes: 2 additions & 0 deletions all/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ def subprojects = [
project(':grpc-protobuf-lite'),
project(':grpc-rls'),
project(':grpc-services'),
project(':grpc-servlet'),
project(':grpc-servlet-jakarta'),
project(':grpc-stub'),
project(':grpc-testing'),
project(':grpc-xds'),
Expand Down
37 changes: 37 additions & 0 deletions examples/example-servlet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Hello World Example using Servlets

This example uses Java Servlets instead of Netty for the gRPC server. This example requires `grpc-java`
and `protoc-gen-grpc-java` to already be built. You are strongly encouraged to check out a git release
tag, since these builds will already be available.

```bash
git checkout v<major>.<minor>.<patch>
```
Otherwise, you must follow [COMPILING](../../COMPILING.md).

To build the example,

1. **[Install gRPC Java library SNAPSHOT locally, including code generation plugin](../../COMPILING.md) (Only need this step for non-released versions, e.g. master HEAD).**

2. In this directory, build the war file
```bash
$ ../gradlew war
```

To run this, deploy the war, now found in `build/libs/example-servlet.war` to your choice of servlet
container. Note that this container must support the Servlet 4.0 spec, for this particular example must
use `javax.servlet` packages instead of the more modern `jakarta.servlet`, though there is a `grpc-servlet-jakarta`
artifact that can be used for Jakarta support. Be sure to enable http/2 support in the servlet container,
or clients will not be able to connect.

To test that this is working properly, build the HelloWorldClient example and direct it to connect to your
http/2 server. From the parent directory:

1. Build the executables:
```bash
$ ../gradlew installDist
```
2. Run the client app, specifying the name to say hello to and the server's address:
```bash
$ ./build/install/examples/bin/hello-world-client World localhost:8080
```
46 changes: 46 additions & 0 deletions examples/example-servlet/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
plugins {
// ASSUMES GRADLE 5.6 OR HIGHER. Use plugin version 0.8.10 with earlier gradle versions
id 'com.google.protobuf' version '0.8.17'
// Generate IntelliJ IDEA's .idea & .iml project files
id 'idea'
id 'war'
}

repositories {
maven { // The google mirror is less flaky than mavenCentral()
url "https://maven-central.storage-download.googleapis.com/maven2/" }
mavenLocal()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

def grpcVersion = '1.53.0-SNAPSHOT' // CURRENT_GRPC_VERSION
def protocVersion = '3.21.7'

dependencies {
implementation "io.grpc:grpc-protobuf:${grpcVersion}",
"io.grpc:grpc-servlet:${grpcVersion}",
"io.grpc:grpc-stub:${grpcVersion}"

providedImplementation "javax.servlet:javax.servlet-api:4.0.1",
"org.apache.tomcat:annotations-api:6.0.53"
}

protobuf {
protoc { artifact = "com.google.protobuf:protoc:${protocVersion}" }
plugins { grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" } }
generateProtoTasks {
all()*.plugins { grpc {} }
}
}

// Inform IDEs like IntelliJ IDEA, Eclipse or NetBeans about the generated code.
sourceSets {
main {
java {
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/java'
}
}
}
8 changes: 8 additions & 0 deletions examples/example-servlet/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pluginManagement {
repositories {
maven { // The google mirror is less flaky than mavenCentral()
url "https://maven-central.storage-download.googleapis.com/maven2/"
}
gradlePluginPortal()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2018 The 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.
*/

package io.grpc.servlet.examples.helloworld;

import io.grpc.stub.StreamObserver;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.servlet.ServletAdapter;
import io.grpc.servlet.ServletServerBuilder;
import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* A servlet that hosts a gRPC server over HTTP/2 and shares the resource URI for the normal servlet
* clients over HTTP/1.0+.
*
* <p>For creating a servlet that solely serves gRPC services, do not follow this example, simply
* extend or register a {@link io.grpc.servlet.GrpcServlet} instead.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to build out such an example/docs - since servlets are instantiated via their default constructor, it can be irritating expose the set of bindableservices that will be expected to be served (via a runtime Set), while also offering a configuration like this annotation that describes the urls to map to.

This might suggest offering a Filter in addition to a Servlet, which can check its set of bindings and only handle the call if it matches (checking the req.getRequestURI().substring(1) as ServletAdapter.doPost does, and comparing against its set), otherwise letting some later filter/servlet take over. It could also perform the content-type check.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should have an example to use extension of GrpcServlet directly, maybe implementing the routeguide service, in addition to the existing example.

As for Filter, that might be something we can add after this PR being merged, and have this PR only support the most basic servlet API. Same for the grpc-web support.

*/
@WebServlet(urlPatterns = {"/helloworld.Greeter/SayHello"}, asyncSupported = true)
public class HelloWorldServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

private final ServletAdapter servletAdapter =
new ServletServerBuilder().addService(new GreeterImpl()).buildServletAdapter();

private static final class GreeterImpl extends GreeterGrpc.GreeterImplBase {
GreeterImpl() {}

@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.setContentType("text/html");
response.getWriter().println("<p>Hello World!</p>");
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
if (ServletAdapter.isGrpc(request)) {
servletAdapter.doPost(request, response);
} else {
response.setContentType("text/html");
response.getWriter().println("<p>Hello non-gRPC client!</p>");
}
}

@Override
public void destroy() {
servletAdapter.destroy();
super.destroy();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2015 The 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";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Need this file for deployment to GlassFish -->
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
<class-loader delegate="false"/>
</glassfish-web-app>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Need this file for deployment to WildFly -->
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.jboss.com/xml/ns/javaee
http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
<context-root>/</context-root>
</jboss-web>
Original file line number Diff line number Diff line change
Expand Up @@ -244,11 +244,8 @@ public ServerStreamTracer newServerStreamTracer(String fullMethodName, Metadata

protected static final Empty EMPTY = Empty.getDefaultInstance();

private void startServer() {
maybeStartHandshakerServer();
ServerBuilder<?> builder = getServerBuilder();
private void configBuilder(@Nullable ServerBuilder<?> builder) {
if (builder == null) {
server = null;
return;
}
testServiceExecutor = Executors.newScheduledThreadPool(2);
Expand All @@ -266,6 +263,14 @@ private void startServer() {
new TestServiceImpl(testServiceExecutor),
allInterceptors))
.addStreamTracerFactory(serverStreamTracerFactory);
}

protected void startServer(@Nullable ServerBuilder<?> builder) {
maybeStartHandshakerServer();
if (builder == null) {
server = null;
return;
}

try {
server = builder.build().start();
Expand Down Expand Up @@ -333,7 +338,9 @@ public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
*/
@Before
public void setUp() {
startServer();
ServerBuilder<?> serverBuilder = getServerBuilder();
configBuilder(serverBuilder);
startServer(serverBuilder);
channel = createChannel();

blockingStub =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

package io.grpc.netty;

import com.google.common.annotations.VisibleForTesting;
import io.grpc.Internal;
import io.grpc.internal.ClientTransportFactory;
import io.grpc.internal.GrpcUtil;
import io.grpc.internal.SharedResourcePool;
import io.grpc.internal.TransportTracer;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
Expand Down Expand Up @@ -107,5 +109,11 @@ public static ClientTransportFactory buildTransportFactory(NettyChannelBuilder b
return builder.buildTransportFactory();
}

@VisibleForTesting
public static void setTransportTracerFactory(
NettyChannelBuilder builder, TransportTracer.Factory factory) {
builder.setTransportTracerFactory(factory);
}

private InternalNettyChannelBuilder() {}
}