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