docs: public CountDownLatch routeChat() {
      info("*** RouteChat");
      final CountDownLatch finishLatch = new CountDownLatch(1);
      StreamObserver<RouteNote> requestObserver =
          asyncStub.routeChat(new StreamObserver<RouteNote>() {
            @Override
            public void onNext(RouteNote note) {
              info("Got message \"{0}\" at {1}, {2}", note.getMessage(), note.getLocation()
                  .getLatitude(), note.getLocation().getLongitude());
              if (testHelper != null) {
                testHelper.onMessage(note);
              }
            }
  
            @Override
            public void onError(Throwable t) {
              warning("RouteChat Failed: {0}", Status.fromThrowable(t));
              if (testHelper != null) {
                testHelper.onRpcError(t);
              }
              finishLatch.countDown();
            }
  
            @Override
            public void onCompleted() {
              info("Finished RouteChat");
              finishLatch.countDown();
            }
          });
  
      try {
        RouteNote[] requests =
            {newNote("First message", 0, 0), newNote("Second message", 0, 1),
                newNote("Third message", 1, 0), newNote("Fourth message", 1, 1)};
  
        for (RouteNote request : requests) {
          info("Sending message \"{0}\" at {1}, {2}", request.getMessage(), request.getLocation()
              .getLatitude(), request.getLocation().getLongitude());
          requestObserver.onNext(request);
        }
      } catch (RuntimeException e) {
        // Cancel RPC
        requestObserver.onError(e);
        throw e;
      }
      // Mark the end of requests
      requestObserver.onCompleted();
  
      // return the latch while receiving happens asynchronously
      return finishLatch;
    }