• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "java_generator.h"
2 
3 #include <algorithm>
4 #include <iostream>
5 #include <iterator>
6 #include <map>
7 #include <set>
8 #include <vector>
9 #include <google/protobuf/compiler/java/java_names.h>
10 #include <google/protobuf/descriptor.h>
11 #include <google/protobuf/descriptor.pb.h>
12 #include <google/protobuf/io/printer.h>
13 #include <google/protobuf/io/zero_copy_stream.h>
14 
15 // Stringify helpers used solely to cast GRPC_VERSION
16 #ifndef STR
17 #define STR(s) #s
18 #endif
19 
20 #ifndef XSTR
21 #define XSTR(s) STR(s)
22 #endif
23 
24 #ifndef FALLTHROUGH_INTENDED
25 #define FALLTHROUGH_INTENDED
26 #endif
27 
28 namespace java_grpc_generator {
29 
30 using google::protobuf::FileDescriptor;
31 using google::protobuf::ServiceDescriptor;
32 using google::protobuf::MethodDescriptor;
33 using google::protobuf::Descriptor;
34 using google::protobuf::io::Printer;
35 using google::protobuf::SourceLocation;
36 using std::to_string;
37 
38 // java keywords from: https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.9
39 static std::set<string> java_keywords = {
40   "abstract",
41   "assert",
42   "boolean",
43   "break",
44   "byte",
45   "case",
46   "catch",
47   "char",
48   "class",
49   "const",
50   "continue",
51   "default",
52   "do",
53   "double",
54   "else",
55   "enum",
56   "extends",
57   "final",
58   "finally",
59   "float",
60   "for",
61   "goto",
62   "if",
63   "implements",
64   "import",
65   "instanceof",
66   "int",
67   "interface",
68   "long",
69   "native",
70   "new",
71   "package",
72   "private",
73   "protected",
74   "public",
75   "return",
76   "short",
77   "static",
78   "strictfp",
79   "super",
80   "switch",
81   "synchronized",
82   "this",
83   "throw",
84   "throws",
85   "transient",
86   "try",
87   "void",
88   "volatile",
89   "while",
90   // additional ones added by us
91   "true",
92   "false",
93 };
94 
95 // Adjust a method name prefix identifier to follow the JavaBean spec:
96 //   - decapitalize the first letter
97 //   - remove embedded underscores & capitalize the following letter
98 //  Finally, if the result is a reserved java keyword, append an underscore.
MixedLower(const string & word)99 static string MixedLower(const string& word) {
100   string w;
101   w += tolower(word[0]);
102   bool after_underscore = false;
103   for (size_t i = 1; i < word.length(); ++i) {
104     if (word[i] == '_') {
105       after_underscore = true;
106     } else {
107       w += after_underscore ? toupper(word[i]) : word[i];
108       after_underscore = false;
109     }
110   }
111   if (java_keywords.find(w) != java_keywords.end()) {
112     return w + "_";
113   }
114   return w;
115 }
116 
117 // Converts to the identifier to the ALL_UPPER_CASE format.
118 //   - An underscore is inserted where a lower case letter is followed by an
119 //     upper case letter.
120 //   - All letters are converted to upper case
ToAllUpperCase(const string & word)121 static string ToAllUpperCase(const string& word) {
122   string w;
123   for (size_t i = 0; i < word.length(); ++i) {
124     w += toupper(word[i]);
125     if ((i < word.length() - 1) && islower(word[i]) && isupper(word[i + 1])) {
126       w += '_';
127     }
128   }
129   return w;
130 }
131 
LowerMethodName(const MethodDescriptor * method)132 static inline string LowerMethodName(const MethodDescriptor* method) {
133   return MixedLower(method->name());
134 }
135 
MethodPropertiesFieldName(const MethodDescriptor * method)136 static inline string MethodPropertiesFieldName(const MethodDescriptor* method) {
137   return "METHOD_" + ToAllUpperCase(method->name());
138 }
139 
MethodPropertiesGetterName(const MethodDescriptor * method)140 static inline string MethodPropertiesGetterName(const MethodDescriptor* method) {
141   return MixedLower("get_" + method->name() + "_method");
142 }
143 
MethodIdFieldName(const MethodDescriptor * method)144 static inline string MethodIdFieldName(const MethodDescriptor* method) {
145   return "METHODID_" + ToAllUpperCase(method->name());
146 }
147 
ShouldGenerateAsLite(const Descriptor * desc)148 static inline bool ShouldGenerateAsLite(const Descriptor* desc) {
149   return false;
150 }
151 
MessageFullJavaName(bool nano,const Descriptor * desc)152 static inline string MessageFullJavaName(bool nano, const Descriptor* desc) {
153   string name = google::protobuf::compiler::java::ClassName(desc);
154   if (nano && !ShouldGenerateAsLite(desc)) {
155     // XXX: Add "nano" to the original package
156     // (https://github.com/grpc/grpc-java/issues/900)
157     if (isupper(name[0])) {
158       // No java package specified.
159       return "nano." + name;
160     }
161     for (size_t i = 0; i < name.size(); ++i) {
162       if ((name[i] == '.') && (i < (name.size() - 1)) && isupper(name[i + 1])) {
163         return name.substr(0, i + 1) + "nano." + name.substr(i + 1);
164       }
165     }
166   }
167   return name;
168 }
169 
170 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
171 template <typename ITR>
GrpcSplitStringToIteratorUsing(const string & full,const char * delim,ITR & result)172 static void GrpcSplitStringToIteratorUsing(const string& full,
173                                        const char* delim,
174                                        ITR& result) {
175   // Optimize the common case where delim is a single character.
176   if (delim[0] != '\0' && delim[1] == '\0') {
177     char c = delim[0];
178     const char* p = full.data();
179     const char* end = p + full.size();
180     while (p != end) {
181       if (*p == c) {
182         ++p;
183       } else {
184         const char* start = p;
185         while (++p != end && *p != c);
186         *result++ = string(start, p - start);
187       }
188     }
189     return;
190   }
191 
192   string::size_type begin_index, end_index;
193   begin_index = full.find_first_not_of(delim);
194   while (begin_index != string::npos) {
195     end_index = full.find_first_of(delim, begin_index);
196     if (end_index == string::npos) {
197       *result++ = full.substr(begin_index);
198       return;
199     }
200     *result++ = full.substr(begin_index, (end_index - begin_index));
201     begin_index = full.find_first_not_of(delim, end_index);
202   }
203 }
204 
205 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcSplitStringUsing(const string & full,const char * delim,std::vector<string> * result)206 static void GrpcSplitStringUsing(const string& full,
207                              const char* delim,
208                              std::vector<string>* result) {
209   std::back_insert_iterator< std::vector<string> > it(*result);
210   GrpcSplitStringToIteratorUsing(full, delim, it);
211 }
212 
213 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcSplit(const string & full,const char * delim)214 static std::vector<string> GrpcSplit(const string& full, const char* delim) {
215   std::vector<string> result;
216   GrpcSplitStringUsing(full, delim, &result);
217   return result;
218 }
219 
220 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcEscapeJavadoc(const string & input)221 static string GrpcEscapeJavadoc(const string& input) {
222   string result;
223   result.reserve(input.size() * 2);
224 
225   char prev = '*';
226 
227   for (string::size_type i = 0; i < input.size(); i++) {
228     char c = input[i];
229     switch (c) {
230       case '*':
231         // Avoid "/*".
232         if (prev == '/') {
233           result.append("&#42;");
234         } else {
235           result.push_back(c);
236         }
237         break;
238       case '/':
239         // Avoid "*/".
240         if (prev == '*') {
241           result.append("&#47;");
242         } else {
243           result.push_back(c);
244         }
245         break;
246       case '@':
247         // '@' starts javadoc tags including the @deprecated tag, which will
248         // cause a compile-time error if inserted before a declaration that
249         // does not have a corresponding @Deprecated annotation.
250         result.append("&#64;");
251         break;
252       case '<':
253         // Avoid interpretation as HTML.
254         result.append("&lt;");
255         break;
256       case '>':
257         // Avoid interpretation as HTML.
258         result.append("&gt;");
259         break;
260       case '&':
261         // Avoid interpretation as HTML.
262         result.append("&amp;");
263         break;
264       case '\\':
265         // Java interprets Unicode escape sequences anywhere!
266         result.append("&#92;");
267         break;
268       default:
269         result.push_back(c);
270         break;
271     }
272 
273     prev = c;
274   }
275 
276   return result;
277 }
278 
279 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
280 template <typename DescriptorType>
GrpcGetCommentsForDescriptor(const DescriptorType * descriptor)281 static string GrpcGetCommentsForDescriptor(const DescriptorType* descriptor) {
282   SourceLocation location;
283   if (descriptor->GetSourceLocation(&location)) {
284     return location.leading_comments.empty() ?
285       location.trailing_comments : location.leading_comments;
286   }
287   return string();
288 }
289 
290 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcGetDocLines(const string & comments)291 static std::vector<string> GrpcGetDocLines(const string& comments) {
292   if (!comments.empty()) {
293     // TODO(kenton):  Ideally we should parse the comment text as Markdown and
294     //   write it back as HTML, but this requires a Markdown parser.  For now
295     //   we just use <pre> to get fixed-width text formatting.
296 
297     // If the comment itself contains block comment start or end markers,
298     // HTML-escape them so that they don't accidentally close the doc comment.
299     string escapedComments = GrpcEscapeJavadoc(comments);
300 
301     std::vector<string> lines = GrpcSplit(escapedComments, "\n");
302     while (!lines.empty() && lines.back().empty()) {
303       lines.pop_back();
304     }
305     return lines;
306   }
307   return std::vector<string>();
308 }
309 
310 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
311 template <typename DescriptorType>
GrpcGetDocLinesForDescriptor(const DescriptorType * descriptor)312 static std::vector<string> GrpcGetDocLinesForDescriptor(const DescriptorType* descriptor) {
313   return GrpcGetDocLines(GrpcGetCommentsForDescriptor(descriptor));
314 }
315 
316 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcWriteDocCommentBody(Printer * printer,const std::vector<string> & lines,bool surroundWithPreTag)317 static void GrpcWriteDocCommentBody(Printer* printer,
318                                     const std::vector<string>& lines,
319                                     bool surroundWithPreTag) {
320   if (!lines.empty()) {
321     if (surroundWithPreTag) {
322       printer->Print(" * <pre>\n");
323     }
324 
325     for (size_t i = 0; i < lines.size(); i++) {
326       // Most lines should start with a space.  Watch out for lines that start
327       // with a /, since putting that right after the leading asterisk will
328       // close the comment.
329       if (!lines[i].empty() && lines[i][0] == '/') {
330         printer->Print(" * $line$\n", "line", lines[i]);
331       } else {
332         printer->Print(" *$line$\n", "line", lines[i]);
333       }
334     }
335 
336     if (surroundWithPreTag) {
337       printer->Print(" * </pre>\n");
338     }
339   }
340 }
341 
342 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcWriteDocComment(Printer * printer,const string & comments)343 static void GrpcWriteDocComment(Printer* printer, const string& comments) {
344   printer->Print("/**\n");
345   std::vector<string> lines = GrpcGetDocLines(comments);
346   GrpcWriteDocCommentBody(printer, lines, false);
347   printer->Print(" */\n");
348 }
349 
350 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcWriteServiceDocComment(Printer * printer,const ServiceDescriptor * service)351 static void GrpcWriteServiceDocComment(Printer* printer,
352                                        const ServiceDescriptor* service) {
353   // Deviating from protobuf to avoid extraneous docs
354   // (see https://github.com/google/protobuf/issues/1406);
355   printer->Print("/**\n");
356   std::vector<string> lines = GrpcGetDocLinesForDescriptor(service);
357   GrpcWriteDocCommentBody(printer, lines, true);
358   printer->Print(" */\n");
359 }
360 
361 // TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
GrpcWriteMethodDocComment(Printer * printer,const MethodDescriptor * method)362 void GrpcWriteMethodDocComment(Printer* printer,
363                            const MethodDescriptor* method) {
364   // Deviating from protobuf to avoid extraneous docs
365   // (see https://github.com/google/protobuf/issues/1406);
366   printer->Print("/**\n");
367   std::vector<string> lines = GrpcGetDocLinesForDescriptor(method);
368   GrpcWriteDocCommentBody(printer, lines, true);
369   printer->Print(" */\n");
370 }
371 
PrintMethodFields(const ServiceDescriptor * service,std::map<string,string> * vars,Printer * p,ProtoFlavor flavor)372 static void PrintMethodFields(
373     const ServiceDescriptor* service, std::map<string, string>* vars,
374     Printer* p, ProtoFlavor flavor) {
375   p->Print("// Static method descriptors that strictly reflect the proto.\n");
376   (*vars)["service_name"] = service->name();
377   for (int i = 0; i < service->method_count(); ++i) {
378     const MethodDescriptor* method = service->method(i);
379     (*vars)["arg_in_id"] = to_string(2 * i);
380     (*vars)["arg_out_id"] = to_string(2 * i + 1);
381     (*vars)["method_name"] = method->name();
382     (*vars)["input_type"] = MessageFullJavaName(flavor == ProtoFlavor::NANO,
383                                                 method->input_type());
384     (*vars)["output_type"] = MessageFullJavaName(flavor == ProtoFlavor::NANO,
385                                                  method->output_type());
386     (*vars)["method_field_name"] = MethodPropertiesFieldName(method);
387     (*vars)["method_new_field_name"] = MethodPropertiesGetterName(method);
388     (*vars)["method_method_name"] = MethodPropertiesGetterName(method);
389     bool client_streaming = method->client_streaming();
390     bool server_streaming = method->server_streaming();
391     if (client_streaming) {
392       if (server_streaming) {
393         (*vars)["method_type"] = "BIDI_STREAMING";
394       } else {
395         (*vars)["method_type"] = "CLIENT_STREAMING";
396       }
397     } else {
398       if (server_streaming) {
399         (*vars)["method_type"] = "SERVER_STREAMING";
400       } else {
401         (*vars)["method_type"] = "UNARY";
402       }
403     }
404 
405     if (flavor == ProtoFlavor::NANO) {
406       // TODO(zsurocking): we're creating two NanoFactories for each method right now.
407       // We could instead create static NanoFactories and reuse them if some methods
408       // share the same request or response messages.
409       if (!ShouldGenerateAsLite(method->input_type())) {
410         p->Print(
411             *vars,
412             "private static final int ARG_IN_$method_field_name$ = $arg_in_id$;\n");
413       }
414       if (!ShouldGenerateAsLite(method->output_type())) {
415         p->Print(
416             *vars,
417             "private static final int ARG_OUT_$method_field_name$ = $arg_out_id$;\n");
418       }
419       p->Print(
420           *vars,
421           "private static volatile $MethodDescriptor$<$input_type$,\n"
422           "    $output_type$> $method_new_field_name$;\n"
423           "\n"
424           "public static $MethodDescriptor$<$input_type$,\n"
425           "    $output_type$> $method_method_name$() {\n"
426           "  $MethodDescriptor$<$input_type$, $output_type$> $method_new_field_name$;\n"
427           "  if (($method_new_field_name$ = $service_class_name$.$method_new_field_name$) == null) {\n"
428           "    synchronized ($service_class_name$.class) {\n"
429           "      if (($method_new_field_name$ = $service_class_name$.$method_new_field_name$) == null) {\n"
430           "        $service_class_name$.$method_new_field_name$ = $method_new_field_name$ = \n"
431           "            $MethodDescriptor$.<$input_type$, $output_type$>newBuilder()\n"
432           "            .setType($MethodType$.$method_type$)\n"
433           "            .setFullMethodName(generateFullMethodName(\n"
434           "                \"$Package$$service_name$\", \"$method_name$\"))\n"
435           "            .setSampledToLocalTracing(true)\n");
436 
437       (*vars)["ProtoLiteUtils"] = "io.grpc.protobuf.lite.ProtoLiteUtils";
438 
439       if (ShouldGenerateAsLite(method->input_type())) {
440         p->Print(
441             *vars,
442             "            .setRequestMarshaller($ProtoLiteUtils$.marshaller(\n"
443             "                $input_type$.getDefaultInstance()))\n");
444       } else {
445         p->Print(
446             *vars,
447             "            .setRequestMarshaller($NanoUtils$.<$input_type$>marshaller(\n"
448             "                new NanoFactory<$input_type$>(ARG_IN_$method_field_name$)))\n");
449       }
450       if (ShouldGenerateAsLite(method->output_type())) {
451         p->Print(
452             *vars,
453             "            .setResponseMarshaller($ProtoLiteUtils$.marshaller(\n"
454             "                $output_type$.getDefaultInstance()))\n");
455       } else {
456         p->Print(
457             *vars,
458             "            .setResponseMarshaller($NanoUtils$.<$output_type$>marshaller(\n"
459             "                new NanoFactory<$output_type$>(ARG_OUT_$method_field_name$)))\n");
460       }
461       p->Print(
462           *vars,
463           "            .build();\n"
464           "      }\n"
465           "    }\n"
466           "  }\n"
467           "  return $method_new_field_name$;\n"
468           "}\n"
469           "\n");
470     } else {
471       if (flavor == ProtoFlavor::LITE) {
472         (*vars)["ProtoUtils"] = "io.grpc.protobuf.lite.ProtoLiteUtils";
473       } else {
474         (*vars)["ProtoUtils"] = "io.grpc.protobuf.ProtoUtils";
475       }
476       p->Print(
477           *vars,
478           "private static volatile $MethodDescriptor$<$input_type$,\n"
479           "    $output_type$> $method_new_field_name$;\n"
480           "\n"
481           "@$RpcMethod$(\n"
482           "    fullMethodName = SERVICE_NAME + '/' + \"$method_name$\",\n"
483           "    requestType = $input_type$.class,\n"
484           "    responseType = $output_type$.class,\n"
485           "    methodType = $MethodType$.$method_type$)\n"
486           "public static $MethodDescriptor$<$input_type$,\n"
487           "    $output_type$> $method_method_name$() {\n"
488           "  $MethodDescriptor$<$input_type$, $output_type$> $method_new_field_name$;\n"
489           "  if (($method_new_field_name$ = $service_class_name$.$method_new_field_name$) == null) {\n"
490           "    synchronized ($service_class_name$.class) {\n"
491           "      if (($method_new_field_name$ = $service_class_name$.$method_new_field_name$) == null) {\n"
492           "        $service_class_name$.$method_new_field_name$ = $method_new_field_name$ = \n"
493           "            $MethodDescriptor$.<$input_type$, $output_type$>newBuilder()\n"
494           "            .setType($MethodType$.$method_type$)\n"
495           "            .setFullMethodName(generateFullMethodName(\n"
496           "                \"$Package$$service_name$\", \"$method_name$\"))\n"
497           "            .setSampledToLocalTracing(true)\n"
498           "            .setRequestMarshaller($ProtoUtils$.marshaller(\n"
499           "                $input_type$.getDefaultInstance()))\n"
500           "            .setResponseMarshaller($ProtoUtils$.marshaller(\n"
501           "                $output_type$.getDefaultInstance()))\n");
502 
503       (*vars)["proto_method_descriptor_supplier"] = service->name() + "MethodDescriptorSupplier";
504       if (flavor == ProtoFlavor::NORMAL) {
505         p->Print(
506             *vars,
507           "                .setSchemaDescriptor(new $proto_method_descriptor_supplier$(\"$method_name$\"))\n");
508       }
509 
510       p->Print(
511           *vars,
512           "                .build();\n");
513       p->Print(*vars,
514           "        }\n"
515           "      }\n"
516           "   }\n"
517           "   return $method_new_field_name$;\n"
518           "}\n"
519           "\n");
520     }
521   }
522 
523   if (flavor == ProtoFlavor::NANO) {
524     p->Print(
525         *vars,
526         "private static final class NanoFactory<T extends com.google.protobuf.nano.MessageNano>\n"
527         "    implements io.grpc.protobuf.nano.MessageNanoFactory<T> {\n"
528         "  private final int id;\n"
529         "\n"
530         "  NanoFactory(int id) {\n"
531         "    this.id = id;\n"
532         "  }\n"
533         "\n"
534         "  @$Override$\n"
535         "  public T newInstance() {\n"
536         "    Object o;\n"
537         "    switch (id) {\n");
538     bool generate_nano = true;
539     for (int i = 0; i < service->method_count(); ++i) {
540       const MethodDescriptor* method = service->method(i);
541       (*vars)["input_type"] = MessageFullJavaName(generate_nano,
542                                                   method->input_type());
543       (*vars)["output_type"] = MessageFullJavaName(generate_nano,
544                                                    method->output_type());
545       (*vars)["method_field_name"] = MethodPropertiesFieldName(method);
546       if (!ShouldGenerateAsLite(method->input_type())) {
547         p->Print(
548             *vars,
549             "    case ARG_IN_$method_field_name$:\n"
550             "      o = new $input_type$();\n"
551             "      break;\n");
552       }
553       if (!ShouldGenerateAsLite(method->output_type())) {
554         p->Print(
555             *vars,
556             "    case ARG_OUT_$method_field_name$:\n"
557             "      o = new $output_type$();\n"
558             "      break;\n");
559       }
560     }
561     p->Print(
562         "    default:\n"
563         "      throw new AssertionError();\n"
564         "    }\n"
565         "    @java.lang.SuppressWarnings(\"unchecked\")\n"
566         "    T t = (T) o;\n"
567         "    return t;\n"
568         "  }\n"
569         "}\n"
570         "\n");
571   }
572 }
573 
574 enum StubType {
575   ASYNC_INTERFACE = 0,
576   BLOCKING_CLIENT_INTERFACE = 1,
577   FUTURE_CLIENT_INTERFACE = 2,
578   BLOCKING_SERVER_INTERFACE = 3,
579   ASYNC_CLIENT_IMPL = 4,
580   BLOCKING_CLIENT_IMPL = 5,
581   FUTURE_CLIENT_IMPL = 6,
582   ABSTRACT_CLASS = 7,
583 };
584 
585 enum CallType {
586   ASYNC_CALL = 0,
587   BLOCKING_CALL = 1,
588   FUTURE_CALL = 2
589 };
590 
591 static void PrintBindServiceMethodBody(const ServiceDescriptor* service,
592                                    std::map<string, string>* vars,
593                                    Printer* p,
594                                    bool generate_nano);
595 
596 // Prints a client interface or implementation class, or a server interface.
PrintStub(const ServiceDescriptor * service,std::map<string,string> * vars,Printer * p,StubType type,bool generate_nano)597 static void PrintStub(
598     const ServiceDescriptor* service,
599     std::map<string, string>* vars,
600     Printer* p, StubType type, bool generate_nano) {
601   const string service_name = service->name();
602   (*vars)["service_name"] = service_name;
603   (*vars)["abstract_name"] = service_name + "ImplBase";
604   string stub_name = service_name;
605   string client_name = service_name;
606   CallType call_type;
607   bool impl_base = false;
608   bool interface = false;
609   switch (type) {
610     case ABSTRACT_CLASS:
611       call_type = ASYNC_CALL;
612       impl_base = true;
613       break;
614     case ASYNC_CLIENT_IMPL:
615       call_type = ASYNC_CALL;
616       stub_name += "Stub";
617       break;
618     case BLOCKING_CLIENT_INTERFACE:
619       interface = true;
620       FALLTHROUGH_INTENDED;
621     case BLOCKING_CLIENT_IMPL:
622       call_type = BLOCKING_CALL;
623       stub_name += "BlockingStub";
624       client_name += "BlockingClient";
625       break;
626     case FUTURE_CLIENT_INTERFACE:
627       interface = true;
628       FALLTHROUGH_INTENDED;
629     case FUTURE_CLIENT_IMPL:
630       call_type = FUTURE_CALL;
631       stub_name += "FutureStub";
632       client_name += "FutureClient";
633       break;
634     case ASYNC_INTERFACE:
635       call_type = ASYNC_CALL;
636       interface = true;
637       break;
638     default:
639       GRPC_CODEGEN_FAIL << "Cannot determine class name for StubType: " << type;
640   }
641   (*vars)["stub_name"] = stub_name;
642   (*vars)["client_name"] = client_name;
643 
644   // Class head
645   if (!interface) {
646     GrpcWriteServiceDocComment(p, service);
647   }
648 
649   if (service->options().deprecated()) {
650     p->Print(*vars, "@$Deprecated$\n");
651   }
652 
653   if (impl_base) {
654     p->Print(
655         *vars,
656         "public static abstract class $abstract_name$ implements $BindableService$ {\n");
657   } else {
658     p->Print(
659         *vars,
660         "public static final class $stub_name$ extends $AbstractStub$<$stub_name$> {\n");
661   }
662   p->Indent();
663 
664   // Constructor and build() method
665   if (!impl_base && !interface) {
666     p->Print(
667         *vars,
668         "private $stub_name$($Channel$ channel) {\n");
669     p->Indent();
670     p->Print("super(channel);\n");
671     p->Outdent();
672     p->Print("}\n\n");
673     p->Print(
674         *vars,
675         "private $stub_name$($Channel$ channel,\n"
676         "    $CallOptions$ callOptions) {\n");
677     p->Indent();
678     p->Print("super(channel, callOptions);\n");
679     p->Outdent();
680     p->Print("}\n\n");
681     p->Print(
682         *vars,
683         "@$Override$\n"
684         "protected $stub_name$ build($Channel$ channel,\n"
685         "    $CallOptions$ callOptions) {\n");
686     p->Indent();
687     p->Print(
688         *vars,
689         "return new $stub_name$(channel, callOptions);\n");
690     p->Outdent();
691     p->Print("}\n");
692   }
693 
694   // RPC methods
695   for (int i = 0; i < service->method_count(); ++i) {
696     const MethodDescriptor* method = service->method(i);
697     (*vars)["input_type"] = MessageFullJavaName(generate_nano,
698                                                 method->input_type());
699     (*vars)["output_type"] = MessageFullJavaName(generate_nano,
700                                                  method->output_type());
701     (*vars)["lower_method_name"] = LowerMethodName(method);
702     (*vars)["method_method_name"] = MethodPropertiesGetterName(method);
703     bool client_streaming = method->client_streaming();
704     bool server_streaming = method->server_streaming();
705 
706     if (call_type == BLOCKING_CALL && client_streaming) {
707       // Blocking client interface with client streaming is not available
708       continue;
709     }
710 
711     if (call_type == FUTURE_CALL && (client_streaming || server_streaming)) {
712       // Future interface doesn't support streaming.
713       continue;
714     }
715 
716     // Method signature
717     p->Print("\n");
718     // TODO(nmittler): Replace with WriteMethodDocComment once included by the protobuf distro.
719     if (!interface) {
720       GrpcWriteMethodDocComment(p, method);
721     }
722 
723     if (method->options().deprecated()) {
724       p->Print(*vars, "@$Deprecated$\n");
725     }
726 
727     p->Print("public ");
728     switch (call_type) {
729       case BLOCKING_CALL:
730         GRPC_CODEGEN_CHECK(!client_streaming)
731             << "Blocking client interface with client streaming is unavailable";
732         if (server_streaming) {
733           // Server streaming
734           p->Print(
735               *vars,
736               "$Iterator$<$output_type$> $lower_method_name$(\n"
737               "    $input_type$ request)");
738         } else {
739           // Simple RPC
740           p->Print(
741               *vars,
742               "$output_type$ $lower_method_name$($input_type$ request)");
743         }
744         break;
745       case ASYNC_CALL:
746         if (client_streaming) {
747           // Bidirectional streaming or client streaming
748           p->Print(
749               *vars,
750               "$StreamObserver$<$input_type$> $lower_method_name$(\n"
751               "    $StreamObserver$<$output_type$> responseObserver)");
752         } else {
753           // Server streaming or simple RPC
754           p->Print(
755               *vars,
756               "void $lower_method_name$($input_type$ request,\n"
757               "    $StreamObserver$<$output_type$> responseObserver)");
758         }
759         break;
760       case FUTURE_CALL:
761         GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming)
762             << "Future interface doesn't support streaming. "
763             << "client_streaming=" << client_streaming << ", "
764             << "server_streaming=" << server_streaming;
765         p->Print(
766             *vars,
767             "$ListenableFuture$<$output_type$> $lower_method_name$(\n"
768             "    $input_type$ request)");
769         break;
770     }
771 
772     if (interface) {
773       p->Print(";\n");
774       continue;
775     }
776     // Method body.
777     p->Print(" {\n");
778     p->Indent();
779     if (impl_base) {
780       switch (call_type) {
781         // NB: Skipping validation of service methods. If something is wrong, we wouldn't get to
782         // this point as compiler would return errors when generating service interface.
783         case ASYNC_CALL:
784           if (client_streaming) {
785             p->Print(
786                 *vars,
787                 "return asyncUnimplementedStreamingCall($method_method_name$(), responseObserver);\n");
788           } else {
789             p->Print(
790                 *vars,
791                 "asyncUnimplementedUnaryCall($method_method_name$(), responseObserver);\n");
792           }
793           break;
794         default:
795           break;
796       }
797     } else if (!interface) {
798       switch (call_type) {
799         case BLOCKING_CALL:
800           GRPC_CODEGEN_CHECK(!client_streaming)
801               << "Blocking client streaming interface is not available";
802           if (server_streaming) {
803             (*vars)["calls_method"] = "blockingServerStreamingCall";
804             (*vars)["params"] = "request";
805           } else {
806             (*vars)["calls_method"] = "blockingUnaryCall";
807             (*vars)["params"] = "request";
808           }
809           p->Print(
810               *vars,
811               "return $calls_method$(\n"
812               "    getChannel(), $method_method_name$(), getCallOptions(), $params$);\n");
813           break;
814         case ASYNC_CALL:
815           if (server_streaming) {
816             if (client_streaming) {
817               (*vars)["calls_method"] = "asyncBidiStreamingCall";
818               (*vars)["params"] = "responseObserver";
819             } else {
820               (*vars)["calls_method"] = "asyncServerStreamingCall";
821               (*vars)["params"] = "request, responseObserver";
822             }
823           } else {
824             if (client_streaming) {
825               (*vars)["calls_method"] = "asyncClientStreamingCall";
826               (*vars)["params"] = "responseObserver";
827             } else {
828               (*vars)["calls_method"] = "asyncUnaryCall";
829               (*vars)["params"] = "request, responseObserver";
830             }
831           }
832           (*vars)["last_line_prefix"] = client_streaming ? "return " : "";
833           p->Print(
834               *vars,
835               "$last_line_prefix$$calls_method$(\n"
836               "    getChannel().newCall($method_method_name$(), getCallOptions()), $params$);\n");
837           break;
838         case FUTURE_CALL:
839           GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming)
840               << "Future interface doesn't support streaming. "
841               << "client_streaming=" << client_streaming << ", "
842               << "server_streaming=" << server_streaming;
843           (*vars)["calls_method"] = "futureUnaryCall";
844           p->Print(
845               *vars,
846               "return $calls_method$(\n"
847               "    getChannel().newCall($method_method_name$(), getCallOptions()), request);\n");
848           break;
849       }
850     }
851     p->Outdent();
852     p->Print("}\n");
853   }
854 
855   if (impl_base) {
856     p->Print("\n");
857     p->Print(
858         *vars,
859         "@$Override$ public final $ServerServiceDefinition$ bindService() {\n");
860     (*vars)["instance"] = "this";
861     PrintBindServiceMethodBody(service, vars, p, generate_nano);
862     p->Print("}\n");
863   }
864 
865   p->Outdent();
866   p->Print("}\n\n");
867 }
868 
CompareMethodClientStreaming(const MethodDescriptor * method1,const MethodDescriptor * method2)869 static bool CompareMethodClientStreaming(const MethodDescriptor* method1,
870                                          const MethodDescriptor* method2)
871 {
872   return method1->client_streaming() < method2->client_streaming();
873 }
874 
875 // Place all method invocations into a single class to reduce memory footprint
876 // on Android.
PrintMethodHandlerClass(const ServiceDescriptor * service,std::map<string,string> * vars,Printer * p,bool generate_nano)877 static void PrintMethodHandlerClass(const ServiceDescriptor* service,
878                                    std::map<string, string>* vars,
879                                    Printer* p,
880                                    bool generate_nano) {
881   // Sort method ids based on client_streaming() so switch tables are compact.
882   std::vector<const MethodDescriptor*> sorted_methods(service->method_count());
883   for (int i = 0; i < service->method_count(); ++i) {
884     sorted_methods[i] = service->method(i);
885   }
886   stable_sort(sorted_methods.begin(), sorted_methods.end(),
887               CompareMethodClientStreaming);
888   for (size_t i = 0; i < sorted_methods.size(); i++) {
889     const MethodDescriptor* method = sorted_methods[i];
890     (*vars)["method_id"] = to_string(i);
891     (*vars)["method_id_name"] = MethodIdFieldName(method);
892     p->Print(
893         *vars,
894         "private static final int $method_id_name$ = $method_id$;\n");
895   }
896   p->Print("\n");
897   (*vars)["service_name"] = service->name() + "ImplBase";
898   p->Print(
899       *vars,
900       "private static final class MethodHandlers<Req, Resp> implements\n"
901       "    io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,\n"
902       "    io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,\n"
903       "    io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,\n"
904       "    io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {\n"
905       "  private final $service_name$ serviceImpl;\n"
906       "  private final int methodId;\n"
907       "\n"
908       "  MethodHandlers($service_name$ serviceImpl, int methodId) {\n"
909       "    this.serviceImpl = serviceImpl;\n"
910       "    this.methodId = methodId;\n"
911       "  }\n\n");
912   p->Indent();
913   p->Print(
914       *vars,
915       "@$Override$\n"
916       "@java.lang.SuppressWarnings(\"unchecked\")\n"
917       "public void invoke(Req request, $StreamObserver$<Resp> responseObserver) {\n"
918       "  switch (methodId) {\n");
919   p->Indent();
920   p->Indent();
921 
922   for (int i = 0; i < service->method_count(); ++i) {
923     const MethodDescriptor* method = service->method(i);
924     if (method->client_streaming()) {
925       continue;
926     }
927     (*vars)["method_id_name"] = MethodIdFieldName(method);
928     (*vars)["lower_method_name"] = LowerMethodName(method);
929     (*vars)["input_type"] = MessageFullJavaName(generate_nano,
930                                                 method->input_type());
931     (*vars)["output_type"] = MessageFullJavaName(generate_nano,
932                                                  method->output_type());
933     p->Print(
934         *vars,
935         "case $method_id_name$:\n"
936         "  serviceImpl.$lower_method_name$(($input_type$) request,\n"
937         "      ($StreamObserver$<$output_type$>) responseObserver);\n"
938         "  break;\n");
939   }
940   p->Print("default:\n"
941            "  throw new AssertionError();\n");
942 
943   p->Outdent();
944   p->Outdent();
945   p->Print("  }\n"
946            "}\n\n");
947 
948   p->Print(
949       *vars,
950       "@$Override$\n"
951       "@java.lang.SuppressWarnings(\"unchecked\")\n"
952       "public $StreamObserver$<Req> invoke(\n"
953       "    $StreamObserver$<Resp> responseObserver) {\n"
954       "  switch (methodId) {\n");
955   p->Indent();
956   p->Indent();
957 
958   for (int i = 0; i < service->method_count(); ++i) {
959     const MethodDescriptor* method = service->method(i);
960     if (!method->client_streaming()) {
961       continue;
962     }
963     (*vars)["method_id_name"] = MethodIdFieldName(method);
964     (*vars)["lower_method_name"] = LowerMethodName(method);
965     (*vars)["input_type"] = MessageFullJavaName(generate_nano,
966                                                 method->input_type());
967     (*vars)["output_type"] = MessageFullJavaName(generate_nano,
968                                                  method->output_type());
969     p->Print(
970         *vars,
971         "case $method_id_name$:\n"
972         "  return ($StreamObserver$<Req>) serviceImpl.$lower_method_name$(\n"
973         "      ($StreamObserver$<$output_type$>) responseObserver);\n");
974   }
975   p->Print("default:\n"
976            "  throw new AssertionError();\n");
977 
978   p->Outdent();
979   p->Outdent();
980   p->Print("  }\n"
981            "}\n");
982 
983 
984   p->Outdent();
985   p->Print("}\n\n");
986 }
987 
PrintGetServiceDescriptorMethod(const ServiceDescriptor * service,std::map<string,string> * vars,Printer * p,ProtoFlavor flavor)988 static void PrintGetServiceDescriptorMethod(const ServiceDescriptor* service,
989                                    std::map<string, string>* vars,
990                                    Printer* p,
991                                    ProtoFlavor flavor) {
992   (*vars)["service_name"] = service->name();
993 
994 
995   if (flavor == ProtoFlavor::NORMAL) {
996     (*vars)["proto_base_descriptor_supplier"] = service->name() + "BaseDescriptorSupplier";
997     (*vars)["proto_file_descriptor_supplier"] = service->name() + "FileDescriptorSupplier";
998     (*vars)["proto_method_descriptor_supplier"] = service->name() + "MethodDescriptorSupplier";
999     (*vars)["proto_class_name"] = google::protobuf::compiler::java::ClassName(service->file());
1000     p->Print(
1001         *vars,
1002         "private static abstract class $proto_base_descriptor_supplier$\n"
1003         "    implements $ProtoFileDescriptorSupplier$, $ProtoServiceDescriptorSupplier$ {\n"
1004         "  $proto_base_descriptor_supplier$() {}\n"
1005         "\n"
1006         "  @$Override$\n"
1007         "  public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() {\n"
1008         "    return $proto_class_name$.getDescriptor();\n"
1009         "  }\n"
1010         "\n"
1011         "  @$Override$\n"
1012         "  public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() {\n"
1013         "    return getFileDescriptor().findServiceByName(\"$service_name$\");\n"
1014         "  }\n"
1015         "}\n"
1016         "\n"
1017         "private static final class $proto_file_descriptor_supplier$\n"
1018         "    extends $proto_base_descriptor_supplier$ {\n"
1019         "  $proto_file_descriptor_supplier$() {}\n"
1020         "}\n"
1021         "\n"
1022         "private static final class $proto_method_descriptor_supplier$\n"
1023         "    extends $proto_base_descriptor_supplier$\n"
1024         "    implements $ProtoMethodDescriptorSupplier$ {\n"
1025         "  private final String methodName;\n"
1026         "\n"
1027         "  $proto_method_descriptor_supplier$(String methodName) {\n"
1028         "    this.methodName = methodName;\n"
1029         "  }\n"
1030         "\n"
1031         "  @$Override$\n"
1032         "  public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() {\n"
1033         "    return getServiceDescriptor().findMethodByName(methodName);\n"
1034         "  }\n"
1035         "}\n\n");
1036   }
1037 
1038   p->Print(
1039       *vars,
1040       "private static volatile $ServiceDescriptor$ serviceDescriptor;\n\n");
1041 
1042   p->Print(
1043       *vars,
1044       "public static $ServiceDescriptor$ getServiceDescriptor() {\n");
1045   p->Indent();
1046   p->Print(
1047       *vars,
1048       "$ServiceDescriptor$ result = serviceDescriptor;\n");
1049   p->Print("if (result == null) {\n");
1050   p->Indent();
1051   p->Print(
1052       *vars,
1053       "synchronized ($service_class_name$.class) {\n");
1054   p->Indent();
1055   p->Print("result = serviceDescriptor;\n");
1056   p->Print("if (result == null) {\n");
1057   p->Indent();
1058 
1059   p->Print(
1060       *vars,
1061       "serviceDescriptor = result = $ServiceDescriptor$.newBuilder(SERVICE_NAME)");
1062   p->Indent();
1063   p->Indent();
1064   if (flavor == ProtoFlavor::NORMAL) {
1065     p->Print(
1066         *vars,
1067         "\n.setSchemaDescriptor(new $proto_file_descriptor_supplier$())");
1068   }
1069   for (int i = 0; i < service->method_count(); ++i) {
1070     const MethodDescriptor* method = service->method(i);
1071     (*vars)["method_method_name"] = MethodPropertiesGetterName(method);
1072     p->Print(*vars, "\n.addMethod($method_method_name$())");
1073   }
1074   p->Print("\n.build();\n");
1075   p->Outdent();
1076   p->Outdent();
1077 
1078   p->Outdent();
1079   p->Print("}\n");
1080   p->Outdent();
1081   p->Print("}\n");
1082   p->Outdent();
1083   p->Print("}\n");
1084   p->Print("return result;\n");
1085   p->Outdent();
1086   p->Print("}\n");
1087 }
1088 
PrintBindServiceMethodBody(const ServiceDescriptor * service,std::map<string,string> * vars,Printer * p,bool generate_nano)1089 static void PrintBindServiceMethodBody(const ServiceDescriptor* service,
1090                                    std::map<string, string>* vars,
1091                                    Printer* p,
1092                                    bool generate_nano) {
1093   (*vars)["service_name"] = service->name();
1094   p->Indent();
1095   p->Print(*vars,
1096            "return "
1097            "$ServerServiceDefinition$.builder(getServiceDescriptor())\n");
1098   p->Indent();
1099   p->Indent();
1100   for (int i = 0; i < service->method_count(); ++i) {
1101     const MethodDescriptor* method = service->method(i);
1102     (*vars)["lower_method_name"] = LowerMethodName(method);
1103     (*vars)["method_method_name"] = MethodPropertiesGetterName(method);
1104     (*vars)["input_type"] = MessageFullJavaName(generate_nano,
1105                                                 method->input_type());
1106     (*vars)["output_type"] = MessageFullJavaName(generate_nano,
1107                                                  method->output_type());
1108     (*vars)["method_id_name"] = MethodIdFieldName(method);
1109     bool client_streaming = method->client_streaming();
1110     bool server_streaming = method->server_streaming();
1111     if (client_streaming) {
1112       if (server_streaming) {
1113         (*vars)["calls_method"] = "asyncBidiStreamingCall";
1114       } else {
1115         (*vars)["calls_method"] = "asyncClientStreamingCall";
1116       }
1117     } else {
1118       if (server_streaming) {
1119         (*vars)["calls_method"] = "asyncServerStreamingCall";
1120       } else {
1121         (*vars)["calls_method"] = "asyncUnaryCall";
1122       }
1123     }
1124     p->Print(*vars, ".addMethod(\n");
1125     p->Indent();
1126     p->Print(
1127         *vars,
1128         "$method_method_name$(),\n"
1129         "$calls_method$(\n");
1130     p->Indent();
1131     p->Print(
1132         *vars,
1133         "new MethodHandlers<\n"
1134         "  $input_type$,\n"
1135         "  $output_type$>(\n"
1136         "    $instance$, $method_id_name$)))\n");
1137     p->Outdent();
1138     p->Outdent();
1139   }
1140   p->Print(".build();\n");
1141   p->Outdent();
1142   p->Outdent();
1143   p->Outdent();
1144 }
1145 
PrintService(const ServiceDescriptor * service,std::map<string,string> * vars,Printer * p,ProtoFlavor flavor,bool disable_version)1146 static void PrintService(const ServiceDescriptor* service,
1147                          std::map<string, string>* vars,
1148                          Printer* p,
1149                          ProtoFlavor flavor,
1150                          bool disable_version) {
1151   (*vars)["service_name"] = service->name();
1152   (*vars)["file_name"] = service->file()->name();
1153   (*vars)["service_class_name"] = ServiceClassName(service);
1154   (*vars)["grpc_version"] = "";
1155   #ifdef GRPC_VERSION
1156   if (!disable_version) {
1157     (*vars)["grpc_version"] = " (version " XSTR(GRPC_VERSION) ")";
1158   }
1159   #endif
1160   // TODO(nmittler): Replace with WriteServiceDocComment once included by protobuf distro.
1161   GrpcWriteServiceDocComment(p, service);
1162   p->Print(
1163       *vars,
1164       "@$Generated$(\n"
1165       "    value = \"by gRPC proto compiler$grpc_version$\",\n"
1166       "    comments = \"Source: $file_name$\")\n");
1167 
1168   if (service->options().deprecated()) {
1169     p->Print(*vars, "@$Deprecated$\n");
1170   }
1171 
1172   p->Print(
1173       *vars,
1174       "public final class $service_class_name$ {\n\n");
1175   p->Indent();
1176   p->Print(
1177       *vars,
1178       "private $service_class_name$() {}\n\n");
1179 
1180   p->Print(
1181       *vars,
1182       "public static final String SERVICE_NAME = "
1183       "\"$Package$$service_name$\";\n\n");
1184 
1185   PrintMethodFields(service, vars, p, flavor);
1186 
1187   // TODO(nmittler): Replace with WriteDocComment once included by protobuf distro.
1188   GrpcWriteDocComment(p, " Creates a new async stub that supports all call types for the service");
1189   p->Print(
1190       *vars,
1191       "public static $service_name$Stub newStub($Channel$ channel) {\n");
1192   p->Indent();
1193   p->Print(
1194       *vars,
1195       "return new $service_name$Stub(channel);\n");
1196   p->Outdent();
1197   p->Print("}\n\n");
1198 
1199   // TODO(nmittler): Replace with WriteDocComment once included by protobuf distro.
1200   GrpcWriteDocComment(p, " Creates a new blocking-style stub that supports unary and streaming "
1201                          "output calls on the service");
1202   p->Print(
1203       *vars,
1204       "public static $service_name$BlockingStub newBlockingStub(\n"
1205       "    $Channel$ channel) {\n");
1206   p->Indent();
1207   p->Print(
1208       *vars,
1209       "return new $service_name$BlockingStub(channel);\n");
1210   p->Outdent();
1211   p->Print("}\n\n");
1212 
1213   // TODO(nmittler): Replace with WriteDocComment once included by protobuf distro.
1214   GrpcWriteDocComment(p, " Creates a new ListenableFuture-style stub that supports unary calls "
1215                          "on the service");
1216   p->Print(
1217       *vars,
1218       "public static $service_name$FutureStub newFutureStub(\n"
1219       "    $Channel$ channel) {\n");
1220   p->Indent();
1221   p->Print(
1222       *vars,
1223       "return new $service_name$FutureStub(channel);\n");
1224   p->Outdent();
1225   p->Print("}\n\n");
1226 
1227   bool generate_nano = flavor == ProtoFlavor::NANO;
1228   PrintStub(service, vars, p, ABSTRACT_CLASS, generate_nano);
1229   PrintStub(service, vars, p, ASYNC_CLIENT_IMPL, generate_nano);
1230   PrintStub(service, vars, p, BLOCKING_CLIENT_IMPL, generate_nano);
1231   PrintStub(service, vars, p, FUTURE_CLIENT_IMPL, generate_nano);
1232 
1233   PrintMethodHandlerClass(service, vars, p, generate_nano);
1234   PrintGetServiceDescriptorMethod(service, vars, p, flavor);
1235   p->Outdent();
1236   p->Print("}\n");
1237 }
1238 
PrintImports(Printer * p,bool generate_nano)1239 void PrintImports(Printer* p, bool generate_nano) {
1240   p->Print(
1241       "import static "
1242       "io.grpc.MethodDescriptor.generateFullMethodName;\n"
1243       "import static "
1244       "io.grpc.stub.ClientCalls.asyncBidiStreamingCall;\n"
1245       "import static "
1246       "io.grpc.stub.ClientCalls.asyncClientStreamingCall;\n"
1247       "import static "
1248       "io.grpc.stub.ClientCalls.asyncServerStreamingCall;\n"
1249       "import static "
1250       "io.grpc.stub.ClientCalls.asyncUnaryCall;\n"
1251       "import static "
1252       "io.grpc.stub.ClientCalls.blockingServerStreamingCall;\n"
1253       "import static "
1254       "io.grpc.stub.ClientCalls.blockingUnaryCall;\n"
1255       "import static "
1256       "io.grpc.stub.ClientCalls.futureUnaryCall;\n"
1257       "import static "
1258       "io.grpc.stub.ServerCalls.asyncBidiStreamingCall;\n"
1259       "import static "
1260       "io.grpc.stub.ServerCalls.asyncClientStreamingCall;\n"
1261       "import static "
1262       "io.grpc.stub.ServerCalls.asyncServerStreamingCall;\n"
1263       "import static "
1264       "io.grpc.stub.ServerCalls.asyncUnaryCall;\n"
1265       "import static "
1266       "io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;\n"
1267       "import static "
1268       "io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;\n\n");
1269   if (generate_nano) {
1270     p->Print("import java.io.IOException;\n\n");
1271   }
1272 }
1273 
GenerateService(const ServiceDescriptor * service,google::protobuf::io::ZeroCopyOutputStream * out,ProtoFlavor flavor,bool disable_version)1274 void GenerateService(const ServiceDescriptor* service,
1275                      google::protobuf::io::ZeroCopyOutputStream* out,
1276                      ProtoFlavor flavor,
1277                      bool disable_version) {
1278   // All non-generated classes must be referred by fully qualified names to
1279   // avoid collision with generated classes.
1280   std::map<string, string> vars;
1281   vars["String"] = "java.lang.String";
1282   vars["Deprecated"] = "java.lang.Deprecated";
1283   vars["Override"] = "java.lang.Override";
1284   vars["Channel"] = "io.grpc.Channel";
1285   vars["CallOptions"] = "io.grpc.CallOptions";
1286   vars["MethodType"] = "io.grpc.MethodDescriptor.MethodType";
1287   vars["ServerMethodDefinition"] =
1288       "io.grpc.ServerMethodDefinition";
1289   vars["BindableService"] = "io.grpc.BindableService";
1290   vars["ServerServiceDefinition"] =
1291       "io.grpc.ServerServiceDefinition";
1292   vars["ServiceDescriptor"] =
1293       "io.grpc.ServiceDescriptor";
1294   vars["ProtoFileDescriptorSupplier"] =
1295       "io.grpc.protobuf.ProtoFileDescriptorSupplier";
1296   vars["ProtoServiceDescriptorSupplier"] =
1297       "io.grpc.protobuf.ProtoServiceDescriptorSupplier";
1298   vars["ProtoMethodDescriptorSupplier"] =
1299       "io.grpc.protobuf.ProtoMethodDescriptorSupplier";
1300   vars["AbstractStub"] = "io.grpc.stub.AbstractStub";
1301   vars["RpcMethod"] = "io.grpc.stub.annotations.RpcMethod";
1302   vars["MethodDescriptor"] = "io.grpc.MethodDescriptor";
1303   vars["NanoUtils"] = "io.grpc.protobuf.nano.NanoUtils";
1304   vars["StreamObserver"] = "io.grpc.stub.StreamObserver";
1305   vars["Iterator"] = "java.util.Iterator";
1306   vars["Generated"] = "javax.annotation.Generated";
1307   vars["ListenableFuture"] =
1308       "com.google.common.util.concurrent.ListenableFuture";
1309 
1310   Printer printer(out, '$');
1311   string package_name = ServiceJavaPackage(service->file(),
1312                                            flavor == ProtoFlavor::NANO);
1313   if (!package_name.empty()) {
1314     printer.Print(
1315         "package $package_name$;\n\n",
1316         "package_name", package_name);
1317   }
1318   PrintImports(&printer, flavor == ProtoFlavor::NANO);
1319 
1320   // Package string is used to fully qualify method names.
1321   vars["Package"] = service->file()->package();
1322   if (!vars["Package"].empty()) {
1323     vars["Package"].append(".");
1324   }
1325   PrintService(service, &vars, &printer, flavor, disable_version);
1326 }
1327 
ServiceJavaPackage(const FileDescriptor * file,bool nano)1328 string ServiceJavaPackage(const FileDescriptor* file, bool nano) {
1329   string result = google::protobuf::compiler::java::ClassName(file);
1330   size_t last_dot_pos = result.find_last_of('.');
1331   if (last_dot_pos != string::npos) {
1332     result.resize(last_dot_pos);
1333   } else {
1334     result = "";
1335   }
1336   if (nano) {
1337     if (!result.empty()) {
1338       result += ".";
1339     }
1340     result += "nano";
1341   }
1342   return result;
1343 }
1344 
ServiceClassName(const google::protobuf::ServiceDescriptor * service)1345 string ServiceClassName(const google::protobuf::ServiceDescriptor* service) {
1346   return service->name() + "Grpc";
1347 }
1348 
1349 }  // namespace java_grpc_generator
1350