1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34
35 #include <google/protobuf/compiler/java/java_service.h>
36
37 #include <google/protobuf/io/printer.h>
38 #include <google/protobuf/stubs/strutil.h>
39 #include <google/protobuf/compiler/java/java_context.h>
40 #include <google/protobuf/compiler/java/java_doc_comment.h>
41 #include <google/protobuf/compiler/java/java_helpers.h>
42 #include <google/protobuf/compiler/java/java_name_resolver.h>
43
44 namespace google {
45 namespace protobuf {
46 namespace compiler {
47 namespace java {
48
ServiceGenerator(const ServiceDescriptor * descriptor)49 ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor)
50 : descriptor_(descriptor) {}
51
~ServiceGenerator()52 ServiceGenerator::~ServiceGenerator() {}
53
54 // ===================================================================
ImmutableServiceGenerator(const ServiceDescriptor * descriptor,Context * context)55 ImmutableServiceGenerator::ImmutableServiceGenerator(
56 const ServiceDescriptor* descriptor, Context* context)
57 : ServiceGenerator(descriptor),
58 context_(context),
59 name_resolver_(context->GetNameResolver()) {}
60
~ImmutableServiceGenerator()61 ImmutableServiceGenerator::~ImmutableServiceGenerator() {}
62
Generate(io::Printer * printer)63 void ImmutableServiceGenerator::Generate(io::Printer* printer) {
64 bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
65 WriteServiceDocComment(printer, descriptor_);
66 MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
67 /* immutable = */ true);
68 printer->Print(
69 "public $static$ abstract class $classname$\n"
70 " implements com.google.protobuf.Service {\n",
71 "static", is_own_file ? "" : "static", "classname", descriptor_->name());
72 printer->Indent();
73
74 printer->Print("protected $classname$() {}\n\n", "classname",
75 descriptor_->name());
76
77 GenerateInterface(printer);
78
79 GenerateNewReflectiveServiceMethod(printer);
80 GenerateNewReflectiveBlockingServiceMethod(printer);
81
82 GenerateAbstractMethods(printer);
83
84 // Generate getDescriptor() and getDescriptorForType().
85 printer->Print(
86 "public static final\n"
87 " com.google.protobuf.Descriptors.ServiceDescriptor\n"
88 " getDescriptor() {\n"
89 " return $file$.getDescriptor().getServices().get($index$);\n"
90 "}\n",
91 "file", name_resolver_->GetImmutableClassName(descriptor_->file()),
92 "index", StrCat(descriptor_->index()));
93 GenerateGetDescriptorForType(printer);
94
95 // Generate more stuff.
96 GenerateCallMethod(printer);
97 GenerateGetPrototype(REQUEST, printer);
98 GenerateGetPrototype(RESPONSE, printer);
99 GenerateStub(printer);
100 GenerateBlockingStub(printer);
101
102 // Add an insertion point.
103 printer->Print(
104 "\n"
105 "// @@protoc_insertion_point(class_scope:$full_name$)\n",
106 "full_name", descriptor_->full_name());
107
108 printer->Outdent();
109 printer->Print("}\n\n");
110 }
111
GenerateGetDescriptorForType(io::Printer * printer)112 void ImmutableServiceGenerator::GenerateGetDescriptorForType(
113 io::Printer* printer) {
114 printer->Print(
115 "public final com.google.protobuf.Descriptors.ServiceDescriptor\n"
116 " getDescriptorForType() {\n"
117 " return getDescriptor();\n"
118 "}\n");
119 }
120
GenerateInterface(io::Printer * printer)121 void ImmutableServiceGenerator::GenerateInterface(io::Printer* printer) {
122 printer->Print("public interface Interface {\n");
123 printer->Indent();
124 GenerateAbstractMethods(printer);
125 printer->Outdent();
126 printer->Print("}\n\n");
127 }
128
GenerateNewReflectiveServiceMethod(io::Printer * printer)129 void ImmutableServiceGenerator::GenerateNewReflectiveServiceMethod(
130 io::Printer* printer) {
131 printer->Print(
132 "public static com.google.protobuf.Service newReflectiveService(\n"
133 " final Interface impl) {\n"
134 " return new $classname$() {\n",
135 "classname", descriptor_->name());
136 printer->Indent();
137 printer->Indent();
138
139 for (int i = 0; i < descriptor_->method_count(); i++) {
140 const MethodDescriptor* method = descriptor_->method(i);
141 printer->Print("@java.lang.Override\n");
142 GenerateMethodSignature(printer, method, IS_CONCRETE);
143 printer->Print(
144 " {\n"
145 " impl.$method$(controller, request, done);\n"
146 "}\n\n",
147 "method", UnderscoresToCamelCase(method));
148 }
149
150 printer->Outdent();
151 printer->Print("};\n");
152 printer->Outdent();
153 printer->Print("}\n\n");
154 }
155
GenerateNewReflectiveBlockingServiceMethod(io::Printer * printer)156 void ImmutableServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
157 io::Printer* printer) {
158 printer->Print(
159 "public static com.google.protobuf.BlockingService\n"
160 " newReflectiveBlockingService(final BlockingInterface impl) {\n"
161 " return new com.google.protobuf.BlockingService() {\n");
162 printer->Indent();
163 printer->Indent();
164
165 GenerateGetDescriptorForType(printer);
166
167 GenerateCallBlockingMethod(printer);
168 GenerateGetPrototype(REQUEST, printer);
169 GenerateGetPrototype(RESPONSE, printer);
170
171 printer->Outdent();
172 printer->Print("};\n");
173 printer->Outdent();
174 printer->Print("}\n\n");
175 }
176
GenerateAbstractMethods(io::Printer * printer)177 void ImmutableServiceGenerator::GenerateAbstractMethods(io::Printer* printer) {
178 for (int i = 0; i < descriptor_->method_count(); i++) {
179 const MethodDescriptor* method = descriptor_->method(i);
180 WriteMethodDocComment(printer, method);
181 GenerateMethodSignature(printer, method, IS_ABSTRACT);
182 printer->Print(";\n\n");
183 }
184 }
185
GetOutput(const MethodDescriptor * method)186 std::string ImmutableServiceGenerator::GetOutput(
187 const MethodDescriptor* method) {
188 return name_resolver_->GetImmutableClassName(method->output_type());
189 }
190
GenerateCallMethod(io::Printer * printer)191 void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) {
192 printer->Print(
193 "\n"
194 "public final void callMethod(\n"
195 " com.google.protobuf.Descriptors.MethodDescriptor method,\n"
196 " com.google.protobuf.RpcController controller,\n"
197 " com.google.protobuf.Message request,\n"
198 " com.google.protobuf.RpcCallback<\n"
199 " com.google.protobuf.Message> done) {\n"
200 " if (method.getService() != getDescriptor()) {\n"
201 " throw new java.lang.IllegalArgumentException(\n"
202 " \"Service.callMethod() given method descriptor for wrong \" +\n"
203 " \"service type.\");\n"
204 " }\n"
205 " switch(method.getIndex()) {\n");
206 printer->Indent();
207 printer->Indent();
208
209 for (int i = 0; i < descriptor_->method_count(); i++) {
210 const MethodDescriptor* method = descriptor_->method(i);
211 std::map<std::string, std::string> vars;
212 vars["index"] = StrCat(i);
213 vars["method"] = UnderscoresToCamelCase(method);
214 vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
215 vars["output"] = GetOutput(method);
216 printer->Print(
217 vars,
218 "case $index$:\n"
219 " this.$method$(controller, ($input$)request,\n"
220 " com.google.protobuf.RpcUtil.<$output$>specializeCallback(\n"
221 " done));\n"
222 " return;\n");
223 }
224
225 printer->Print(
226 "default:\n"
227 " throw new java.lang.AssertionError(\"Can't get here.\");\n");
228
229 printer->Outdent();
230 printer->Outdent();
231
232 printer->Print(
233 " }\n"
234 "}\n"
235 "\n");
236 }
237
GenerateCallBlockingMethod(io::Printer * printer)238 void ImmutableServiceGenerator::GenerateCallBlockingMethod(
239 io::Printer* printer) {
240 printer->Print(
241 "\n"
242 "public final com.google.protobuf.Message callBlockingMethod(\n"
243 " com.google.protobuf.Descriptors.MethodDescriptor method,\n"
244 " com.google.protobuf.RpcController controller,\n"
245 " com.google.protobuf.Message request)\n"
246 " throws com.google.protobuf.ServiceException {\n"
247 " if (method.getService() != getDescriptor()) {\n"
248 " throw new java.lang.IllegalArgumentException(\n"
249 " \"Service.callBlockingMethod() given method descriptor for \" +\n"
250 " \"wrong service type.\");\n"
251 " }\n"
252 " switch(method.getIndex()) {\n");
253 printer->Indent();
254 printer->Indent();
255
256 for (int i = 0; i < descriptor_->method_count(); i++) {
257 const MethodDescriptor* method = descriptor_->method(i);
258 std::map<std::string, std::string> vars;
259 vars["index"] = StrCat(i);
260 vars["method"] = UnderscoresToCamelCase(method);
261 vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
262 vars["output"] = GetOutput(method);
263 printer->Print(vars,
264 "case $index$:\n"
265 " return impl.$method$(controller, ($input$)request);\n");
266 }
267
268 printer->Print(
269 "default:\n"
270 " throw new java.lang.AssertionError(\"Can't get here.\");\n");
271
272 printer->Outdent();
273 printer->Outdent();
274
275 printer->Print(
276 " }\n"
277 "}\n"
278 "\n");
279 }
280
GenerateGetPrototype(RequestOrResponse which,io::Printer * printer)281 void ImmutableServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
282 io::Printer* printer) {
283 /*
284 * TODO(cpovirk): The exception message says "Service.foo" when it may be
285 * "BlockingService.foo." Consider fixing.
286 */
287 printer->Print(
288 "public final com.google.protobuf.Message\n"
289 " get$request_or_response$Prototype(\n"
290 " com.google.protobuf.Descriptors.MethodDescriptor method) {\n"
291 " if (method.getService() != getDescriptor()) {\n"
292 " throw new java.lang.IllegalArgumentException(\n"
293 " \"Service.get$request_or_response$Prototype() given method \" +\n"
294 " \"descriptor for wrong service type.\");\n"
295 " }\n"
296 " switch(method.getIndex()) {\n",
297 "request_or_response", (which == REQUEST) ? "Request" : "Response");
298 printer->Indent();
299 printer->Indent();
300
301 for (int i = 0; i < descriptor_->method_count(); i++) {
302 const MethodDescriptor* method = descriptor_->method(i);
303 std::map<std::string, std::string> vars;
304 vars["index"] = StrCat(i);
305 vars["type"] =
306 (which == REQUEST)
307 ? name_resolver_->GetImmutableClassName(method->input_type())
308 : GetOutput(method);
309 printer->Print(vars,
310 "case $index$:\n"
311 " return $type$.getDefaultInstance();\n");
312 }
313
314 printer->Print(
315 "default:\n"
316 " throw new java.lang.AssertionError(\"Can't get here.\");\n");
317
318 printer->Outdent();
319 printer->Outdent();
320
321 printer->Print(
322 " }\n"
323 "}\n"
324 "\n");
325 }
326
GenerateStub(io::Printer * printer)327 void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) {
328 printer->Print(
329 "public static Stub newStub(\n"
330 " com.google.protobuf.RpcChannel channel) {\n"
331 " return new Stub(channel);\n"
332 "}\n"
333 "\n"
334 "public static final class Stub extends $classname$ implements Interface "
335 "{"
336 "\n",
337 "classname", name_resolver_->GetImmutableClassName(descriptor_));
338 printer->Indent();
339
340 printer->Print(
341 "private Stub(com.google.protobuf.RpcChannel channel) {\n"
342 " this.channel = channel;\n"
343 "}\n"
344 "\n"
345 "private final com.google.protobuf.RpcChannel channel;\n"
346 "\n"
347 "public com.google.protobuf.RpcChannel getChannel() {\n"
348 " return channel;\n"
349 "}\n");
350
351 for (int i = 0; i < descriptor_->method_count(); i++) {
352 const MethodDescriptor* method = descriptor_->method(i);
353 printer->Print("\n");
354 GenerateMethodSignature(printer, method, IS_CONCRETE);
355 printer->Print(" {\n");
356 printer->Indent();
357
358 std::map<std::string, std::string> vars;
359 vars["index"] = StrCat(i);
360 vars["output"] = GetOutput(method);
361 printer->Print(vars,
362 "channel.callMethod(\n"
363 " getDescriptor().getMethods().get($index$),\n"
364 " controller,\n"
365 " request,\n"
366 " $output$.getDefaultInstance(),\n"
367 " com.google.protobuf.RpcUtil.generalizeCallback(\n"
368 " done,\n"
369 " $output$.class,\n"
370 " $output$.getDefaultInstance()));\n");
371
372 printer->Outdent();
373 printer->Print("}\n");
374 }
375
376 printer->Outdent();
377 printer->Print(
378 "}\n"
379 "\n");
380 }
381
GenerateBlockingStub(io::Printer * printer)382 void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
383 printer->Print(
384 "public static BlockingInterface newBlockingStub(\n"
385 " com.google.protobuf.BlockingRpcChannel channel) {\n"
386 " return new BlockingStub(channel);\n"
387 "}\n"
388 "\n");
389
390 printer->Print("public interface BlockingInterface {");
391 printer->Indent();
392
393 for (int i = 0; i < descriptor_->method_count(); i++) {
394 const MethodDescriptor* method = descriptor_->method(i);
395 GenerateBlockingMethodSignature(printer, method);
396 printer->Print(";\n");
397 }
398
399 printer->Outdent();
400 printer->Print(
401 "}\n"
402 "\n");
403
404 printer->Print(
405 "private static final class BlockingStub implements BlockingInterface "
406 "{\n");
407 printer->Indent();
408
409 printer->Print(
410 "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n"
411 " this.channel = channel;\n"
412 "}\n"
413 "\n"
414 "private final com.google.protobuf.BlockingRpcChannel channel;\n");
415
416 for (int i = 0; i < descriptor_->method_count(); i++) {
417 const MethodDescriptor* method = descriptor_->method(i);
418 GenerateBlockingMethodSignature(printer, method);
419 printer->Print(" {\n");
420 printer->Indent();
421
422 std::map<std::string, std::string> vars;
423 vars["index"] = StrCat(i);
424 vars["output"] = GetOutput(method);
425 printer->Print(vars,
426 "return ($output$) channel.callBlockingMethod(\n"
427 " getDescriptor().getMethods().get($index$),\n"
428 " controller,\n"
429 " request,\n"
430 " $output$.getDefaultInstance());\n");
431
432 printer->Outdent();
433 printer->Print(
434 "}\n"
435 "\n");
436 }
437
438 printer->Outdent();
439 printer->Print("}\n");
440 }
441
GenerateMethodSignature(io::Printer * printer,const MethodDescriptor * method,IsAbstract is_abstract)442 void ImmutableServiceGenerator::GenerateMethodSignature(
443 io::Printer* printer, const MethodDescriptor* method,
444 IsAbstract is_abstract) {
445 std::map<std::string, std::string> vars;
446 vars["name"] = UnderscoresToCamelCase(method);
447 vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
448 vars["output"] = GetOutput(method);
449 vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : "";
450 printer->Print(vars,
451 "public $abstract$ void $name$(\n"
452 " com.google.protobuf.RpcController controller,\n"
453 " $input$ request,\n"
454 " com.google.protobuf.RpcCallback<$output$> done)");
455 }
456
GenerateBlockingMethodSignature(io::Printer * printer,const MethodDescriptor * method)457 void ImmutableServiceGenerator::GenerateBlockingMethodSignature(
458 io::Printer* printer, const MethodDescriptor* method) {
459 std::map<std::string, std::string> vars;
460 vars["method"] = UnderscoresToCamelCase(method);
461 vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
462 vars["output"] = GetOutput(method);
463 printer->Print(vars,
464 "\n"
465 "public $output$ $method$(\n"
466 " com.google.protobuf.RpcController controller,\n"
467 " $input$ request)\n"
468 " throws com.google.protobuf.ServiceException");
469 }
470
471 } // namespace java
472 } // namespace compiler
473 } // namespace protobuf
474 } // namespace google
475