Add javadoc to grpc codegen based on proto docs

Fixes #1612
diff --git a/compiler/src/java_plugin/cpp/java_generator.cpp b/compiler/src/java_plugin/cpp/java_generator.cpp
index 8a65b06..0c4d05b 100644
--- a/compiler/src/java_plugin/cpp/java_generator.cpp
+++ b/compiler/src/java_plugin/cpp/java_generator.cpp
@@ -25,6 +25,7 @@
 using google::protobuf::MethodDescriptor;
 using google::protobuf::Descriptor;
 using google::protobuf::io::Printer;
+using google::protobuf::SourceLocation;
 using std::to_string;
 
 // Adjust a method name prefix identifier to follow the JavaBean spec:
@@ -90,6 +91,208 @@
   return name;
 }
 
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+template <typename ITR>
+static void GrpcSplitStringToIteratorUsing(const string& full,
+                                       const char* delim,
+                                       ITR& result) {
+  // Optimize the common case where delim is a single character.
+  if (delim[0] != '\0' && delim[1] == '\0') {
+    char c = delim[0];
+    const char* p = full.data();
+    const char* end = p + full.size();
+    while (p != end) {
+      if (*p == c) {
+        ++p;
+      } else {
+        const char* start = p;
+        while (++p != end && *p != c);
+        *result++ = string(start, p - start);
+      }
+    }
+    return;
+  }
+
+  string::size_type begin_index, end_index;
+  begin_index = full.find_first_not_of(delim);
+  while (begin_index != string::npos) {
+    end_index = full.find_first_of(delim, begin_index);
+    if (end_index == string::npos) {
+      *result++ = full.substr(begin_index);
+      return;
+    }
+    *result++ = full.substr(begin_index, (end_index - begin_index));
+    begin_index = full.find_first_not_of(delim, end_index);
+  }
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static void GrpcSplitStringUsing(const string& full,
+                             const char* delim,
+                             vector<string>* result) {
+  back_insert_iterator< vector<string> > it(*result);
+  GrpcSplitStringToIteratorUsing(full, delim, it);
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static vector<string> GrpcSplit(const string& full, const char* delim) {
+  vector<string> result;
+  GrpcSplitStringUsing(full, delim, &result);
+  return result;
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static string GrpcEscapeJavadoc(const string& input) {
+  string result;
+  result.reserve(input.size() * 2);
+
+  char prev = '*';
+
+  for (string::size_type i = 0; i < input.size(); i++) {
+    char c = input[i];
+    switch (c) {
+      case '*':
+        // Avoid "/*".
+        if (prev == '/') {
+          result.append("&#42;");
+        } else {
+          result.push_back(c);
+        }
+        break;
+      case '/':
+        // Avoid "*/".
+        if (prev == '*') {
+          result.append("&#47;");
+        } else {
+          result.push_back(c);
+        }
+        break;
+      case '@':
+        // '@' starts javadoc tags including the @deprecated tag, which will
+        // cause a compile-time error if inserted before a declaration that
+        // does not have a corresponding @Deprecated annotation.
+        result.append("&#64;");
+        break;
+      case '<':
+        // Avoid interpretation as HTML.
+        result.append("&lt;");
+        break;
+      case '>':
+        // Avoid interpretation as HTML.
+        result.append("&gt;");
+        break;
+      case '&':
+        // Avoid interpretation as HTML.
+        result.append("&amp;");
+        break;
+      case '\\':
+        // Java interprets Unicode escape sequences anywhere!
+        result.append("&#92;");
+        break;
+      default:
+        result.push_back(c);
+        break;
+    }
+
+    prev = c;
+  }
+
+  return result;
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+template <typename DescriptorType>
+static string GrpcGetCommentsForDescriptor(const DescriptorType* descriptor) {
+  SourceLocation location;
+  if (descriptor->GetSourceLocation(&location)) {
+    return location.leading_comments.empty() ?
+      location.trailing_comments : location.leading_comments;
+  }
+  return string();
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static vector<string> GrpcGetDocLines(const string& comments) {
+  if (!comments.empty()) {
+    // TODO(kenton):  Ideally we should parse the comment text as Markdown and
+    //   write it back as HTML, but this requires a Markdown parser.  For now
+    //   we just use <pre> to get fixed-width text formatting.
+
+    // If the comment itself contains block comment start or end markers,
+    // HTML-escape them so that they don't accidentally close the doc comment.
+    string escapedComments = GrpcEscapeJavadoc(comments);
+
+    vector<string> lines = GrpcSplit(escapedComments, "\n");
+    while (!lines.empty() && lines.back().empty()) {
+      lines.pop_back();
+    }
+    return lines;
+  }
+  return vector<string>();
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+template <typename DescriptorType>
+static vector<string> GrpcGetDocLinesForDescriptor(const DescriptorType* descriptor) {
+  return GrpcGetDocLines(GrpcGetCommentsForDescriptor(descriptor));
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static void GrpcWriteDocCommentBody(Printer* printer,
+                                    const vector<string>& lines,
+                                    bool surroundWithPreTag) {
+  if (!lines.empty()) {
+    if (surroundWithPreTag) {
+      printer->Print(" * <pre>\n");
+    }
+
+    for (int i = 0; i < lines.size(); i++) {
+      // Most lines should start with a space.  Watch out for lines that start
+      // with a /, since putting that right after the leading asterisk will
+      // close the comment.
+      if (!lines[i].empty() && lines[i][0] == '/') {
+        printer->Print(" * $line$\n", "line", lines[i]);
+      } else {
+        printer->Print(" *$line$\n", "line", lines[i]);
+      }
+    }
+
+    if (surroundWithPreTag) {
+      printer->Print(" * </pre>\n");
+    }
+  }
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static void GrpcWriteDocComment(Printer* printer, const string& comments) {
+  printer->Print("/**\n");
+  vector<string> lines = GrpcGetDocLines(comments);
+  GrpcWriteDocCommentBody(printer, lines, false);
+  printer->Print(" */\n");
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static void GrpcWriteServiceDocComment(Printer* printer,
+                                       const ServiceDescriptor* service) {
+  // Deviating from protobuf to avoid extraneous docs
+  // (see https://github.com/google/protobuf/issues/1406);
+  printer->Print("/**\n");
+  vector<string> lines = GrpcGetDocLinesForDescriptor(service);
+  GrpcWriteDocCommentBody(printer, lines, true);
+  printer->Print(" */\n");
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+void GrpcWriteMethodDocComment(Printer* printer,
+                           const MethodDescriptor* method) {
+  // Deviating from protobuf to avoid extraneous docs
+  // (see https://github.com/google/protobuf/issues/1406);
+  printer->Print("/**\n");
+  vector<string> lines = GrpcGetDocLinesForDescriptor(method);
+  GrpcWriteDocCommentBody(printer, lines, true);
+  printer->Print(" */\n");
+}
+
 static void PrintMethodFields(
     const ServiceDescriptor* service, map<string, string>* vars, Printer* p,
     ProtoFlavor flavor) {
@@ -293,6 +496,7 @@
   (*vars)["interface_name"] = interface_name;
   (*vars)["impl_name"] = impl_name;
 
+  bool interface = !abstract && !impl;
   // Class head
   if (abstract) {
     p->Print(
@@ -300,7 +504,10 @@
         "@$ExperimentalApi$\n"
         "public static abstract class $abstract_name$ implements $service_name$, "
         "$BindableService$ {\n");
-  } else if (!impl) {
+  } else if (interface) {
+    // TODO(nmittler): Replace with WriteServiceDocComment when included in protobuf distribution.
+    // Print the service-level javadoc when we define the interface.
+    GrpcWriteServiceDocComment(p, service);
     p->Print(
         *vars,
         "public static interface $interface_name$ {\n");
@@ -366,7 +573,10 @@
 
     // Method signature
     p->Print("\n");
-    if (impl || abstract) {
+    if (interface) {
+      // TODO(nmittler): Replace with WriteMethodDocComment once included by the protobuf distro.
+      GrpcWriteMethodDocComment(p, method);
+    } else {
       p->Print(
           *vars,
           "@$Override$\n");
@@ -715,6 +925,8 @@
   #else
     (*vars)["grpc_version"] = "";
   #endif
+  // TODO(nmittler): Replace with WriteServiceDocComment once included by protobuf distro.
+  GrpcWriteServiceDocComment(p, service);
   p->Print(
       *vars,
       "@$Generated$(\n"
@@ -733,6 +945,8 @@
 
   PrintMethodFields(service, vars, p, flavor);
 
+  // TODO(nmittler): Replace with WriteDocComment once included by protobuf distro.
+  GrpcWriteDocComment(p, " Creates a new async stub that supports all call types for the service");
   p->Print(
       *vars,
       "public static $service_name$Stub newStub($Channel$ channel) {\n");
@@ -742,6 +956,10 @@
       "return new $service_name$Stub(channel);\n");
   p->Outdent();
   p->Print("}\n\n");
+
+  // TODO(nmittler): Replace with WriteDocComment once included by protobuf distro.
+  GrpcWriteDocComment(p, " Creates a new blocking-style stub that supports unary and streaming "
+                         "output calls on the service");
   p->Print(
       *vars,
       "public static $service_name$BlockingStub newBlockingStub(\n"
@@ -752,6 +970,10 @@
       "return new $service_name$BlockingStub(channel);\n");
   p->Outdent();
   p->Print("}\n\n");
+
+  // TODO(nmittler): Replace with WriteDocComment once included by protobuf distro.
+  GrpcWriteDocComment(p, " Creates a new ListenableFuture-style stub that supports unary and "
+                         "streaming output calls on the service");
   p->Print(
       *vars,
       "public static $service_name$FutureStub newFutureStub(\n"
diff --git a/compiler/src/test/golden/TestService.java.txt b/compiler/src/test/golden/TestService.java.txt
index 57691bf..535313a 100644
--- a/compiler/src/test/golden/TestService.java.txt
+++ b/compiler/src/test/golden/TestService.java.txt
@@ -15,6 +15,11 @@
 import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
 import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;
 
+/**
+ * <pre>
+ * Test service that supports all call types.
+ * </pre>
+ */
 @javax.annotation.Generated(
     value = "by gRPC proto compiler (version 0.14.0-SNAPSHOT)",
     comments = "Source: test.proto")
@@ -71,34 +76,81 @@
           io.grpc.protobuf.ProtoUtils.marshaller(io.grpc.testing.integration.Test.StreamingOutputCallRequest.getDefaultInstance()),
           io.grpc.protobuf.ProtoUtils.marshaller(io.grpc.testing.integration.Test.StreamingOutputCallResponse.getDefaultInstance()));
 
+  /**
+   * Creates a new async stub that supports all call types for the service
+   */
   public static TestServiceStub newStub(io.grpc.Channel channel) {
     return new TestServiceStub(channel);
   }
 
+  /**
+   * Creates a new blocking-style stub that supports unary and streaming output calls on the service
+   */
   public static TestServiceBlockingStub newBlockingStub(
       io.grpc.Channel channel) {
     return new TestServiceBlockingStub(channel);
   }
 
+  /**
+   * Creates a new ListenableFuture-style stub that supports unary and streaming output calls on the service
+   */
   public static TestServiceFutureStub newFutureStub(
       io.grpc.Channel channel) {
     return new TestServiceFutureStub(channel);
   }
 
+  /**
+   * <pre>
+   * Test service that supports all call types.
+   * </pre>
+   */
   public static interface TestService {
 
+    /**
+     * <pre>
+     * One request followed by one response.
+     * The server returns the client payload as-is.
+     * </pre>
+     */
     public void unaryCall(io.grpc.testing.integration.Test.SimpleRequest request,
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.SimpleResponse> responseObserver);
 
+    /**
+     * <pre>
+     * One request followed by a sequence of responses (streamed download).
+     * The server returns the payload with client desired type and sizes.
+     * </pre>
+     */
     public void streamingOutputCall(io.grpc.testing.integration.Test.StreamingOutputCallRequest request,
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse> responseObserver);
 
+    /**
+     * <pre>
+     * A sequence of requests followed by one response (streamed upload).
+     * The server returns the aggregated size of client payload as the result.
+     * </pre>
+     */
     public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingInputCallRequest> streamingInputCall(
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingInputCallResponse> responseObserver);
 
+    /**
+     * <pre>
+     * 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 bidirectionality.
+     * </pre>
+     */
     public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallRequest> fullBidiCall(
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse> responseObserver);
 
+    /**
+     * <pre>
+     * 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.
+     * </pre>
+     */
     public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallRequest> halfBidiCall(
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse> responseObserver);
   }
@@ -141,16 +193,44 @@
     }
   }
 
+  /**
+   * <pre>
+   * Test service that supports all call types.
+   * </pre>
+   */
   public static interface TestServiceBlockingClient {
 
+    /**
+     * <pre>
+     * One request followed by one response.
+     * The server returns the client payload as-is.
+     * </pre>
+     */
     public io.grpc.testing.integration.Test.SimpleResponse unaryCall(io.grpc.testing.integration.Test.SimpleRequest request);
 
+    /**
+     * <pre>
+     * One request followed by a sequence of responses (streamed download).
+     * The server returns the payload with client desired type and sizes.
+     * </pre>
+     */
     public java.util.Iterator<io.grpc.testing.integration.Test.StreamingOutputCallResponse> streamingOutputCall(
         io.grpc.testing.integration.Test.StreamingOutputCallRequest request);
   }
 
+  /**
+   * <pre>
+   * Test service that supports all call types.
+   * </pre>
+   */
   public static interface TestServiceFutureClient {
 
+    /**
+     * <pre>
+     * One request followed by one response.
+     * The server returns the client payload as-is.
+     * </pre>
+     */
     public com.google.common.util.concurrent.ListenableFuture<io.grpc.testing.integration.Test.SimpleResponse> unaryCall(
         io.grpc.testing.integration.Test.SimpleRequest request);
   }
diff --git a/compiler/src/test/proto/test.proto b/compiler/src/test/proto/test.proto
index 5b4a267..dfaaed5 100644
--- a/compiler/src/test/proto/test.proto
+++ b/compiler/src/test/proto/test.proto
@@ -23,6 +23,7 @@
 message StreamingOutputCallResponse {
 }
 
+// Test service that supports all call types.
 service TestService {
   // One request followed by one response.
   // The server returns the client payload as-is.
diff --git a/compiler/src/testLite/golden/TestService.java.txt b/compiler/src/testLite/golden/TestService.java.txt
index 31002c9..90343fd 100644
--- a/compiler/src/testLite/golden/TestService.java.txt
+++ b/compiler/src/testLite/golden/TestService.java.txt
@@ -15,6 +15,11 @@
 import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
 import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;
 
+/**
+ * <pre>
+ * Test service that supports all call types.
+ * </pre>
+ */
 @javax.annotation.Generated(
     value = "by gRPC proto compiler (version 0.14.0-SNAPSHOT)",
     comments = "Source: test.proto")
@@ -71,34 +76,81 @@
           io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.Test.StreamingOutputCallRequest.getDefaultInstance()),
           io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.Test.StreamingOutputCallResponse.getDefaultInstance()));
 
+  /**
+   * Creates a new async stub that supports all call types for the service
+   */
   public static TestServiceStub newStub(io.grpc.Channel channel) {
     return new TestServiceStub(channel);
   }
 
+  /**
+   * Creates a new blocking-style stub that supports unary and streaming output calls on the service
+   */
   public static TestServiceBlockingStub newBlockingStub(
       io.grpc.Channel channel) {
     return new TestServiceBlockingStub(channel);
   }
 
+  /**
+   * Creates a new ListenableFuture-style stub that supports unary and streaming output calls on the service
+   */
   public static TestServiceFutureStub newFutureStub(
       io.grpc.Channel channel) {
     return new TestServiceFutureStub(channel);
   }
 
+  /**
+   * <pre>
+   * Test service that supports all call types.
+   * </pre>
+   */
   public static interface TestService {
 
+    /**
+     * <pre>
+     * One request followed by one response.
+     * The server returns the client payload as-is.
+     * </pre>
+     */
     public void unaryCall(io.grpc.testing.integration.Test.SimpleRequest request,
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.SimpleResponse> responseObserver);
 
+    /**
+     * <pre>
+     * One request followed by a sequence of responses (streamed download).
+     * The server returns the payload with client desired type and sizes.
+     * </pre>
+     */
     public void streamingOutputCall(io.grpc.testing.integration.Test.StreamingOutputCallRequest request,
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse> responseObserver);
 
+    /**
+     * <pre>
+     * A sequence of requests followed by one response (streamed upload).
+     * The server returns the aggregated size of client payload as the result.
+     * </pre>
+     */
     public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingInputCallRequest> streamingInputCall(
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingInputCallResponse> responseObserver);
 
+    /**
+     * <pre>
+     * 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 bidirectionality.
+     * </pre>
+     */
     public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallRequest> fullBidiCall(
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse> responseObserver);
 
+    /**
+     * <pre>
+     * 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.
+     * </pre>
+     */
     public io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallRequest> halfBidiCall(
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.Test.StreamingOutputCallResponse> responseObserver);
   }
@@ -141,16 +193,44 @@
     }
   }
 
+  /**
+   * <pre>
+   * Test service that supports all call types.
+   * </pre>
+   */
   public static interface TestServiceBlockingClient {
 
+    /**
+     * <pre>
+     * One request followed by one response.
+     * The server returns the client payload as-is.
+     * </pre>
+     */
     public io.grpc.testing.integration.Test.SimpleResponse unaryCall(io.grpc.testing.integration.Test.SimpleRequest request);
 
+    /**
+     * <pre>
+     * One request followed by a sequence of responses (streamed download).
+     * The server returns the payload with client desired type and sizes.
+     * </pre>
+     */
     public java.util.Iterator<io.grpc.testing.integration.Test.StreamingOutputCallResponse> streamingOutputCall(
         io.grpc.testing.integration.Test.StreamingOutputCallRequest request);
   }
 
+  /**
+   * <pre>
+   * Test service that supports all call types.
+   * </pre>
+   */
   public static interface TestServiceFutureClient {
 
+    /**
+     * <pre>
+     * One request followed by one response.
+     * The server returns the client payload as-is.
+     * </pre>
+     */
     public com.google.common.util.concurrent.ListenableFuture<io.grpc.testing.integration.Test.SimpleResponse> unaryCall(
         io.grpc.testing.integration.Test.SimpleRequest request);
   }
diff --git a/compiler/src/testLite/proto/test.proto b/compiler/src/testLite/proto/test.proto
index fb2e3e7..d2a1fd5 100644
--- a/compiler/src/testLite/proto/test.proto
+++ b/compiler/src/testLite/proto/test.proto
@@ -24,6 +24,7 @@
 message StreamingOutputCallResponse {
 }
 
+// Test service that supports all call types.
 service TestService {
   // One request followed by one response.
   // The server returns the client payload as-is.
diff --git a/compiler/src/testNano/golden/TestService.java.txt b/compiler/src/testNano/golden/TestService.java.txt
index 1f2c91c..f0232ec 100644
--- a/compiler/src/testNano/golden/TestService.java.txt
+++ b/compiler/src/testNano/golden/TestService.java.txt
@@ -17,6 +17,11 @@
 
 import java.io.IOException;
 
+/**
+ * <pre>
+ * Test service that supports all call types.
+ * </pre>
+ */
 @javax.annotation.Generated(
     value = "by gRPC proto compiler (version 0.14.0-SNAPSHOT)",
     comments = "Source: test.proto")
@@ -149,34 +154,81 @@
     }
   }
 
+  /**
+   * Creates a new async stub that supports all call types for the service
+   */
   public static TestServiceStub newStub(io.grpc.Channel channel) {
     return new TestServiceStub(channel);
   }
 
+  /**
+   * Creates a new blocking-style stub that supports unary and streaming output calls on the service
+   */
   public static TestServiceBlockingStub newBlockingStub(
       io.grpc.Channel channel) {
     return new TestServiceBlockingStub(channel);
   }
 
+  /**
+   * Creates a new ListenableFuture-style stub that supports unary and streaming output calls on the service
+   */
   public static TestServiceFutureStub newFutureStub(
       io.grpc.Channel channel) {
     return new TestServiceFutureStub(channel);
   }
 
+  /**
+   * <pre>
+   * Test service that supports all call types.
+   * </pre>
+   */
   public static interface TestService {
 
+    /**
+     * <pre>
+     * One request followed by one response.
+     * The server returns the client payload as-is.
+     * </pre>
+     */
     public void unaryCall(io.grpc.testing.integration.nano.Test.SimpleRequest request,
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.SimpleResponse> responseObserver);
 
+    /**
+     * <pre>
+     * One request followed by a sequence of responses (streamed download).
+     * The server returns the payload with client desired type and sizes.
+     * </pre>
+     */
     public void streamingOutputCall(io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest request,
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> responseObserver);
 
+    /**
+     * <pre>
+     * A sequence of requests followed by one response (streamed upload).
+     * The server returns the aggregated size of client payload as the result.
+     * </pre>
+     */
     public io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingInputCallRequest> streamingInputCall(
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingInputCallResponse> responseObserver);
 
+    /**
+     * <pre>
+     * 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 bidirectionality.
+     * </pre>
+     */
     public io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest> fullBidiCall(
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> responseObserver);
 
+    /**
+     * <pre>
+     * 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.
+     * </pre>
+     */
     public io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest> halfBidiCall(
         io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> responseObserver);
   }
@@ -219,16 +271,44 @@
     }
   }
 
+  /**
+   * <pre>
+   * Test service that supports all call types.
+   * </pre>
+   */
   public static interface TestServiceBlockingClient {
 
+    /**
+     * <pre>
+     * One request followed by one response.
+     * The server returns the client payload as-is.
+     * </pre>
+     */
     public io.grpc.testing.integration.nano.Test.SimpleResponse unaryCall(io.grpc.testing.integration.nano.Test.SimpleRequest request);
 
+    /**
+     * <pre>
+     * One request followed by a sequence of responses (streamed download).
+     * The server returns the payload with client desired type and sizes.
+     * </pre>
+     */
     public java.util.Iterator<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> streamingOutputCall(
         io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest request);
   }
 
+  /**
+   * <pre>
+   * Test service that supports all call types.
+   * </pre>
+   */
   public static interface TestServiceFutureClient {
 
+    /**
+     * <pre>
+     * One request followed by one response.
+     * The server returns the client payload as-is.
+     * </pre>
+     */
     public com.google.common.util.concurrent.ListenableFuture<io.grpc.testing.integration.nano.Test.SimpleResponse> unaryCall(
         io.grpc.testing.integration.nano.Test.SimpleRequest request);
   }