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