• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 // Author: kenton@google.com (Kenton Varda)
9 //  Based on original Protocol Buffers design by
10 //  Sanjay Ghemawat, Jeff Dean, and others.
11 
12 #include "google/protobuf/compiler/java/full/service.h"
13 
14 #include "absl/log/absl_log.h"
15 #include "absl/strings/str_cat.h"
16 #include "google/protobuf/compiler/java/context.h"
17 #include "google/protobuf/compiler/java/doc_comment.h"
18 #include "google/protobuf/compiler/java/helpers.h"
19 #include "google/protobuf/compiler/java/name_resolver.h"
20 #include "google/protobuf/io/printer.h"
21 
22 // Must be last.
23 #include "google/protobuf/port_def.inc"
24 
25 namespace google {
26 namespace protobuf {
27 namespace compiler {
28 namespace java {
29 
ImmutableServiceGenerator(const ServiceDescriptor * descriptor,Context * context)30 ImmutableServiceGenerator::ImmutableServiceGenerator(
31     const ServiceDescriptor* descriptor, Context* context)
32     : ServiceGenerator(descriptor),
33       context_(context),
34       name_resolver_(context->GetNameResolver()) {}
35 
~ImmutableServiceGenerator()36 ImmutableServiceGenerator::~ImmutableServiceGenerator() {}
37 
Generate(io::Printer * printer)38 void ImmutableServiceGenerator::Generate(io::Printer* printer) {
39   bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
40   WriteServiceDocComment(printer, descriptor_, context_->options());
41   MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
42                                 /* immutable = */ true);
43   if (!context_->options().opensource_runtime) {
44     printer->Print("@com.google.protobuf.Internal.ProtoNonnullApi\n");
45   }
46 
47   printer->Print(
48       "public $static$ abstract class $classname$\n"
49       "    implements com.google.protobuf.Service {\n",
50       "static", is_own_file ? "" : "static", "classname", descriptor_->name());
51   printer->Indent();
52 
53   printer->Print("protected $classname$() {}\n\n", "classname",
54                  descriptor_->name());
55 
56   GenerateInterface(printer);
57 
58   GenerateNewReflectiveServiceMethod(printer);
59   GenerateNewReflectiveBlockingServiceMethod(printer);
60 
61   GenerateAbstractMethods(printer);
62 
63   // Generate getDescriptor() and getDescriptorForType().
64   printer->Print(
65       "public static final\n"
66       "    com.google.protobuf.Descriptors.ServiceDescriptor\n"
67       "    getDescriptor() {\n"
68       "  return $file$.getDescriptor().getServices().get($index$);\n"
69       "}\n",
70       "file", name_resolver_->GetImmutableClassName(descriptor_->file()),
71       "index", absl::StrCat(descriptor_->index()));
72   GenerateGetDescriptorForType(printer);
73 
74   // Generate more stuff.
75   GenerateCallMethod(printer);
76   GenerateGetPrototype(REQUEST, printer);
77   GenerateGetPrototype(RESPONSE, printer);
78   GenerateStub(printer);
79   GenerateBlockingStub(printer);
80 
81   // Add an insertion point.
82   printer->Print(
83       "\n"
84       "// @@protoc_insertion_point(class_scope:$full_name$)\n",
85       "full_name", descriptor_->full_name());
86 
87   printer->Outdent();
88   printer->Print("}\n\n");
89 }
90 
GenerateGetDescriptorForType(io::Printer * printer)91 void ImmutableServiceGenerator::GenerateGetDescriptorForType(
92     io::Printer* printer) {
93   printer->Print(
94       "public final com.google.protobuf.Descriptors.ServiceDescriptor\n"
95       "    getDescriptorForType() {\n"
96       "  return getDescriptor();\n"
97       "}\n");
98 }
99 
GenerateInterface(io::Printer * printer)100 void ImmutableServiceGenerator::GenerateInterface(io::Printer* printer) {
101   printer->Print("public interface Interface {\n");
102   printer->Indent();
103   GenerateAbstractMethods(printer);
104   printer->Outdent();
105   printer->Print("}\n\n");
106 }
107 
GenerateNewReflectiveServiceMethod(io::Printer * printer)108 void ImmutableServiceGenerator::GenerateNewReflectiveServiceMethod(
109     io::Printer* printer) {
110   printer->Print(
111       "public static com.google.protobuf.Service newReflectiveService(\n"
112       "    final Interface impl) {\n"
113       "  return new $classname$() {\n",
114       "classname", descriptor_->name());
115   printer->Indent();
116   printer->Indent();
117 
118   for (int i = 0; i < descriptor_->method_count(); i++) {
119     const MethodDescriptor* method = descriptor_->method(i);
120     printer->Print("@java.lang.Override\n");
121     GenerateMethodSignature(printer, method, IS_CONCRETE);
122     printer->Print(
123         " {\n"
124         "  impl.$method$(controller, request, done);\n"
125         "}\n\n",
126         "method", UnderscoresToCamelCase(method));
127   }
128 
129   printer->Outdent();
130   printer->Print("};\n");
131   printer->Outdent();
132   printer->Print("}\n\n");
133 }
134 
GenerateNewReflectiveBlockingServiceMethod(io::Printer * printer)135 void ImmutableServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
136     io::Printer* printer) {
137   printer->Print(
138       "public static com.google.protobuf.BlockingService\n"
139       "    newReflectiveBlockingService(final BlockingInterface impl) {\n"
140       "  return new com.google.protobuf.BlockingService() {\n");
141   printer->Indent();
142   printer->Indent();
143 
144   GenerateGetDescriptorForType(printer);
145 
146   GenerateCallBlockingMethod(printer);
147   GenerateGetPrototype(REQUEST, printer);
148   GenerateGetPrototype(RESPONSE, printer);
149 
150   printer->Outdent();
151   printer->Print("};\n");
152   printer->Outdent();
153   printer->Print("}\n\n");
154 }
155 
GenerateAbstractMethods(io::Printer * printer)156 void ImmutableServiceGenerator::GenerateAbstractMethods(io::Printer* printer) {
157   for (int i = 0; i < descriptor_->method_count(); i++) {
158     const MethodDescriptor* method = descriptor_->method(i);
159     WriteMethodDocComment(printer, method, context_->options());
160     GenerateMethodSignature(printer, method, IS_ABSTRACT);
161     printer->Print(";\n\n");
162   }
163 }
164 
GetOutput(const MethodDescriptor * method)165 std::string ImmutableServiceGenerator::GetOutput(
166     const MethodDescriptor* method) {
167   return name_resolver_->GetImmutableClassName(method->output_type());
168 }
169 
GenerateCallMethod(io::Printer * printer)170 void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) {
171   printer->Print(
172       "\n"
173       "public final void callMethod(\n"
174       "    com.google.protobuf.Descriptors.MethodDescriptor method,\n"
175       "    com.google.protobuf.RpcController controller,\n"
176       "    com.google.protobuf.Message request,\n"
177       "    com.google.protobuf.RpcCallback<\n"
178       "      com.google.protobuf.Message> done) {\n"
179       "  if (method.getService() != getDescriptor()) {\n"
180       "    throw new java.lang.IllegalArgumentException(\n"
181       "      \"Service.callMethod() given method descriptor for wrong \" +\n"
182       "      \"service type.\");\n"
183       "  }\n"
184       "  switch(method.getIndex()) {\n");
185   printer->Indent();
186   printer->Indent();
187 
188   for (int i = 0; i < descriptor_->method_count(); i++) {
189     const MethodDescriptor* method = descriptor_->method(i);
190     absl::flat_hash_map<absl::string_view, std::string> vars;
191     vars["index"] = absl::StrCat(i);
192     vars["method"] = UnderscoresToCamelCase(method);
193     vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
194     vars["output"] = GetOutput(method);
195     printer->Print(
196         vars,
197         "case $index$:\n"
198         "  this.$method$(controller, ($input$)request,\n"
199         "    com.google.protobuf.RpcUtil.<$output$>specializeCallback(\n"
200         "      done));\n"
201         "  return;\n");
202   }
203 
204   printer->Print(
205       "default:\n"
206       "  throw new java.lang.AssertionError(\"Can't get here.\");\n");
207 
208   printer->Outdent();
209   printer->Outdent();
210 
211   printer->Print(
212       "  }\n"
213       "}\n"
214       "\n");
215 }
216 
GenerateCallBlockingMethod(io::Printer * printer)217 void ImmutableServiceGenerator::GenerateCallBlockingMethod(
218     io::Printer* printer) {
219   printer->Print(
220       "\n"
221       "public final com.google.protobuf.Message callBlockingMethod(\n"
222       "    com.google.protobuf.Descriptors.MethodDescriptor method,\n"
223       "    com.google.protobuf.RpcController controller,\n"
224       "    com.google.protobuf.Message request)\n"
225       "    throws com.google.protobuf.ServiceException {\n"
226       "  if (method.getService() != getDescriptor()) {\n"
227       "    throw new java.lang.IllegalArgumentException(\n"
228       "      \"Service.callBlockingMethod() given method descriptor for \" +\n"
229       "      \"wrong service type.\");\n"
230       "  }\n"
231       "  switch(method.getIndex()) {\n");
232   printer->Indent();
233   printer->Indent();
234 
235   for (int i = 0; i < descriptor_->method_count(); i++) {
236     const MethodDescriptor* method = descriptor_->method(i);
237     absl::flat_hash_map<absl::string_view, std::string> vars;
238     vars["index"] = absl::StrCat(i);
239     vars["method"] = UnderscoresToCamelCase(method);
240     vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
241     vars["output"] = GetOutput(method);
242     printer->Print(vars,
243                    "case $index$:\n"
244                    "  return impl.$method$(controller, ($input$)request);\n");
245   }
246 
247   printer->Print(
248       "default:\n"
249       "  throw new java.lang.AssertionError(\"Can't get here.\");\n");
250 
251   printer->Outdent();
252   printer->Outdent();
253 
254   printer->Print(
255       "  }\n"
256       "}\n"
257       "\n");
258 }
259 
GenerateGetPrototype(RequestOrResponse which,io::Printer * printer)260 void ImmutableServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
261                                                      io::Printer* printer) {
262   /*
263    * TODO: The exception message says "Service.foo" when it may be
264    * "BlockingService.foo."  Consider fixing.
265    */
266   printer->Print(
267       "public final com.google.protobuf.Message\n"
268       "    get$request_or_response$Prototype(\n"
269       "    com.google.protobuf.Descriptors.MethodDescriptor method) {\n"
270       "  if (method.getService() != getDescriptor()) {\n"
271       "    throw new java.lang.IllegalArgumentException(\n"
272       "      \"Service.get$request_or_response$Prototype() given method \" +\n"
273       "      \"descriptor for wrong service type.\");\n"
274       "  }\n"
275       "  switch(method.getIndex()) {\n",
276       "request_or_response", (which == REQUEST) ? "Request" : "Response");
277   printer->Indent();
278   printer->Indent();
279 
280   for (int i = 0; i < descriptor_->method_count(); i++) {
281     const MethodDescriptor* method = descriptor_->method(i);
282     absl::flat_hash_map<absl::string_view, std::string> vars;
283     vars["index"] = absl::StrCat(i);
284     vars["type"] =
285         (which == REQUEST)
286             ? name_resolver_->GetImmutableClassName(method->input_type())
287             : GetOutput(method);
288     printer->Print(vars,
289                    "case $index$:\n"
290                    "  return $type$.getDefaultInstance();\n");
291   }
292 
293   printer->Print(
294       "default:\n"
295       "  throw new java.lang.AssertionError(\"Can't get here.\");\n");
296 
297   printer->Outdent();
298   printer->Outdent();
299 
300   printer->Print(
301       "  }\n"
302       "}\n"
303       "\n");
304 }
305 
GenerateStub(io::Printer * printer)306 void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) {
307   printer->Print(
308       "public static Stub newStub(\n"
309       "    com.google.protobuf.RpcChannel channel) {\n"
310       "  return new Stub(channel);\n"
311       "}\n"
312       "\n"
313       "public static final class Stub extends $classname$ implements Interface "
314       "{"
315       "\n",
316       "classname", name_resolver_->GetImmutableClassName(descriptor_));
317   printer->Indent();
318 
319   printer->Print(
320       "private Stub(com.google.protobuf.RpcChannel channel) {\n"
321       "  this.channel = channel;\n"
322       "}\n"
323       "\n"
324       "private final com.google.protobuf.RpcChannel channel;\n"
325       "\n"
326       "public com.google.protobuf.RpcChannel getChannel() {\n"
327       "  return channel;\n"
328       "}\n");
329 
330   for (int i = 0; i < descriptor_->method_count(); i++) {
331     const MethodDescriptor* method = descriptor_->method(i);
332     printer->Print("\n");
333     GenerateMethodSignature(printer, method, IS_CONCRETE);
334     printer->Print(" {\n");
335     printer->Indent();
336 
337     absl::flat_hash_map<absl::string_view, std::string> vars;
338     vars["index"] = absl::StrCat(i);
339     vars["output"] = GetOutput(method);
340     printer->Print(vars,
341                    "channel.callMethod(\n"
342                    "  getDescriptor().getMethods().get($index$),\n"
343                    "  controller,\n"
344                    "  request,\n"
345                    "  $output$.getDefaultInstance(),\n"
346                    "  com.google.protobuf.RpcUtil.generalizeCallback(\n"
347                    "    done,\n"
348                    "    $output$.class,\n"
349                    "    $output$.getDefaultInstance()));\n");
350 
351     printer->Outdent();
352     printer->Print("}\n");
353   }
354 
355   printer->Outdent();
356   printer->Print(
357       "}\n"
358       "\n");
359 }
360 
GenerateBlockingStub(io::Printer * printer)361 void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
362   printer->Print(
363       "public static BlockingInterface newBlockingStub(\n"
364       "    com.google.protobuf.BlockingRpcChannel channel) {\n"
365       "  return new BlockingStub(channel);\n"
366       "}\n"
367       "\n");
368 
369   printer->Print("public interface BlockingInterface {");
370   printer->Indent();
371 
372   for (int i = 0; i < descriptor_->method_count(); i++) {
373     const MethodDescriptor* method = descriptor_->method(i);
374     GenerateBlockingMethodSignature(printer, method);
375     printer->Print(";\n");
376   }
377 
378   printer->Outdent();
379   printer->Print(
380       "}\n"
381       "\n");
382 
383   printer->Print(
384       "private static final class BlockingStub implements BlockingInterface "
385       "{\n");
386   printer->Indent();
387 
388   printer->Print(
389       "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n"
390       "  this.channel = channel;\n"
391       "}\n"
392       "\n"
393       "private final com.google.protobuf.BlockingRpcChannel channel;\n");
394 
395   for (int i = 0; i < descriptor_->method_count(); i++) {
396     const MethodDescriptor* method = descriptor_->method(i);
397     GenerateBlockingMethodSignature(printer, method);
398     printer->Print(" {\n");
399     printer->Indent();
400 
401     absl::flat_hash_map<absl::string_view, std::string> vars;
402     vars["index"] = absl::StrCat(i);
403     vars["output"] = GetOutput(method);
404     printer->Print(vars,
405                    "return ($output$) channel.callBlockingMethod(\n"
406                    "  getDescriptor().getMethods().get($index$),\n"
407                    "  controller,\n"
408                    "  request,\n"
409                    "  $output$.getDefaultInstance());\n");
410 
411     printer->Outdent();
412     printer->Print(
413         "}\n"
414         "\n");
415   }
416 
417   printer->Outdent();
418   printer->Print("}\n");
419 }
420 
GenerateMethodSignature(io::Printer * printer,const MethodDescriptor * method,IsAbstract is_abstract)421 void ImmutableServiceGenerator::GenerateMethodSignature(
422     io::Printer* printer, const MethodDescriptor* method,
423     IsAbstract is_abstract) {
424   absl::flat_hash_map<absl::string_view, std::string> vars;
425   vars["name"] = UnderscoresToCamelCase(method);
426   vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
427   vars["output"] = GetOutput(method);
428   vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : "";
429   printer->Print(vars,
430                  "public $abstract$ void $name$(\n"
431                  "    com.google.protobuf.RpcController controller,\n"
432                  "    $input$ request,\n"
433                  "    com.google.protobuf.RpcCallback<$output$> done)");
434 }
435 
GenerateBlockingMethodSignature(io::Printer * printer,const MethodDescriptor * method)436 void ImmutableServiceGenerator::GenerateBlockingMethodSignature(
437     io::Printer* printer, const MethodDescriptor* method) {
438   absl::flat_hash_map<absl::string_view, std::string> vars;
439   vars["method"] = UnderscoresToCamelCase(method);
440   vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
441   vars["output"] = GetOutput(method);
442   printer->Print(vars,
443                  "\n"
444                  "public $output$ $method$(\n"
445                  "    com.google.protobuf.RpcController controller,\n"
446                  "    $input$ request)\n"
447                  "    throws com.google.protobuf.ServiceException");
448 }
449 
450 }  // namespace java
451 }  // namespace compiler
452 }  // namespace protobuf
453 }  // namespace google
454 
455 #include "google/protobuf/port_undef.inc"
456