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