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/stubs/strutil.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), context_(context),
58 name_resolver_(context->GetNameResolver()) {}
59
~ImmutableServiceGenerator()60 ImmutableServiceGenerator::~ImmutableServiceGenerator() {}
61
Generate(io::Printer * printer)62 void ImmutableServiceGenerator::Generate(io::Printer* printer) {
63 bool is_own_file =
64 MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
65 WriteServiceDocComment(printer, descriptor_);
66 printer->Print(
67 "public $static$ abstract class $classname$\n"
68 " implements com.google.protobuf.Service {\n",
69 "static", is_own_file ? "" : "static",
70 "classname", descriptor_->name());
71 printer->Indent();
72
73 printer->Print(
74 "protected $classname$() {}\n\n",
75 "classname", 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", SimpleItoa(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
GenerateCallMethod(io::Printer * printer)186 void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) {
187 printer->Print(
188 "\n"
189 "public final void callMethod(\n"
190 " com.google.protobuf.Descriptors.MethodDescriptor method,\n"
191 " com.google.protobuf.RpcController controller,\n"
192 " com.google.protobuf.Message request,\n"
193 " com.google.protobuf.RpcCallback<\n"
194 " com.google.protobuf.Message> done) {\n"
195 " if (method.getService() != getDescriptor()) {\n"
196 " throw new java.lang.IllegalArgumentException(\n"
197 " \"Service.callMethod() given method descriptor for wrong \" +\n"
198 " \"service type.\");\n"
199 " }\n"
200 " switch(method.getIndex()) {\n");
201 printer->Indent();
202 printer->Indent();
203
204 for (int i = 0; i < descriptor_->method_count(); i++) {
205 const MethodDescriptor* method = descriptor_->method(i);
206 map<string, string> vars;
207 vars["index"] = SimpleItoa(i);
208 vars["method"] = UnderscoresToCamelCase(method);
209 vars["input"] = name_resolver_->GetImmutableClassName(
210 method->input_type());
211 vars["output"] = name_resolver_->GetImmutableClassName(
212 method->output_type());
213 printer->Print(vars,
214 "case $index$:\n"
215 " this.$method$(controller, ($input$)request,\n"
216 " com.google.protobuf.RpcUtil.<$output$>specializeCallback(\n"
217 " done));\n"
218 " return;\n");
219 }
220
221 printer->Print(
222 "default:\n"
223 " throw new java.lang.AssertionError(\"Can't get here.\");\n");
224
225 printer->Outdent();
226 printer->Outdent();
227
228 printer->Print(
229 " }\n"
230 "}\n"
231 "\n");
232 }
233
GenerateCallBlockingMethod(io::Printer * printer)234 void ImmutableServiceGenerator::GenerateCallBlockingMethod(
235 io::Printer* printer) {
236 printer->Print(
237 "\n"
238 "public final com.google.protobuf.Message callBlockingMethod(\n"
239 " com.google.protobuf.Descriptors.MethodDescriptor method,\n"
240 " com.google.protobuf.RpcController controller,\n"
241 " com.google.protobuf.Message request)\n"
242 " throws com.google.protobuf.ServiceException {\n"
243 " if (method.getService() != getDescriptor()) {\n"
244 " throw new java.lang.IllegalArgumentException(\n"
245 " \"Service.callBlockingMethod() given method descriptor for \" +\n"
246 " \"wrong service type.\");\n"
247 " }\n"
248 " switch(method.getIndex()) {\n");
249 printer->Indent();
250 printer->Indent();
251
252 for (int i = 0; i < descriptor_->method_count(); i++) {
253 const MethodDescriptor* method = descriptor_->method(i);
254 map<string, string> vars;
255 vars["index"] = SimpleItoa(i);
256 vars["method"] = UnderscoresToCamelCase(method);
257 vars["input"] = name_resolver_->GetImmutableClassName(
258 method->input_type());
259 vars["output"] = name_resolver_->GetImmutableClassName(
260 method->output_type());
261 printer->Print(vars,
262 "case $index$:\n"
263 " return impl.$method$(controller, ($input$)request);\n");
264 }
265
266 printer->Print(
267 "default:\n"
268 " throw new java.lang.AssertionError(\"Can't get here.\");\n");
269
270 printer->Outdent();
271 printer->Outdent();
272
273 printer->Print(
274 " }\n"
275 "}\n"
276 "\n");
277 }
278
GenerateGetPrototype(RequestOrResponse which,io::Printer * printer)279 void ImmutableServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
280 io::Printer* printer) {
281 /*
282 * TODO(cpovirk): The exception message says "Service.foo" when it may be
283 * "BlockingService.foo." Consider fixing.
284 */
285 printer->Print(
286 "public final com.google.protobuf.Message\n"
287 " get$request_or_response$Prototype(\n"
288 " com.google.protobuf.Descriptors.MethodDescriptor method) {\n"
289 " if (method.getService() != getDescriptor()) {\n"
290 " throw new java.lang.IllegalArgumentException(\n"
291 " \"Service.get$request_or_response$Prototype() given method \" +\n"
292 " \"descriptor for wrong service type.\");\n"
293 " }\n"
294 " switch(method.getIndex()) {\n",
295 "request_or_response", (which == REQUEST) ? "Request" : "Response");
296 printer->Indent();
297 printer->Indent();
298
299 for (int i = 0; i < descriptor_->method_count(); i++) {
300 const MethodDescriptor* method = descriptor_->method(i);
301 map<string, string> vars;
302 vars["index"] = SimpleItoa(i);
303 vars["type"] = name_resolver_->GetImmutableClassName(
304 (which == REQUEST) ? method->input_type() : method->output_type());
305 printer->Print(vars,
306 "case $index$:\n"
307 " return $type$.getDefaultInstance();\n");
308 }
309
310 printer->Print(
311 "default:\n"
312 " throw new java.lang.AssertionError(\"Can't get here.\");\n");
313
314 printer->Outdent();
315 printer->Outdent();
316
317 printer->Print(
318 " }\n"
319 "}\n"
320 "\n");
321 }
322
GenerateStub(io::Printer * printer)323 void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) {
324 printer->Print(
325 "public static Stub newStub(\n"
326 " com.google.protobuf.RpcChannel channel) {\n"
327 " return new Stub(channel);\n"
328 "}\n"
329 "\n"
330 "public static final class Stub extends $classname$ implements Interface {"
331 "\n",
332 "classname", name_resolver_->GetImmutableClassName(descriptor_));
333 printer->Indent();
334
335 printer->Print(
336 "private Stub(com.google.protobuf.RpcChannel channel) {\n"
337 " this.channel = channel;\n"
338 "}\n"
339 "\n"
340 "private final com.google.protobuf.RpcChannel channel;\n"
341 "\n"
342 "public com.google.protobuf.RpcChannel getChannel() {\n"
343 " return channel;\n"
344 "}\n");
345
346 for (int i = 0; i < descriptor_->method_count(); i++) {
347 const MethodDescriptor* method = descriptor_->method(i);
348 printer->Print("\n");
349 GenerateMethodSignature(printer, method, IS_CONCRETE);
350 printer->Print(" {\n");
351 printer->Indent();
352
353 map<string, string> vars;
354 vars["index"] = SimpleItoa(i);
355 vars["output"] = name_resolver_->GetImmutableClassName(
356 method->output_type());
357 printer->Print(vars,
358 "channel.callMethod(\n"
359 " getDescriptor().getMethods().get($index$),\n"
360 " controller,\n"
361 " request,\n"
362 " $output$.getDefaultInstance(),\n"
363 " com.google.protobuf.RpcUtil.generalizeCallback(\n"
364 " done,\n"
365 " $output$.class,\n"
366 " $output$.getDefaultInstance()));\n");
367
368 printer->Outdent();
369 printer->Print("}\n");
370 }
371
372 printer->Outdent();
373 printer->Print(
374 "}\n"
375 "\n");
376 }
377
GenerateBlockingStub(io::Printer * printer)378 void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
379 printer->Print(
380 "public static BlockingInterface newBlockingStub(\n"
381 " com.google.protobuf.BlockingRpcChannel channel) {\n"
382 " return new BlockingStub(channel);\n"
383 "}\n"
384 "\n");
385
386 printer->Print(
387 "public interface BlockingInterface {");
388 printer->Indent();
389
390 for (int i = 0; i < descriptor_->method_count(); i++) {
391 const MethodDescriptor* method = descriptor_->method(i);
392 GenerateBlockingMethodSignature(printer, method);
393 printer->Print(";\n");
394 }
395
396 printer->Outdent();
397 printer->Print(
398 "}\n"
399 "\n");
400
401 printer->Print(
402 "private static final class BlockingStub implements BlockingInterface {\n");
403 printer->Indent();
404
405 printer->Print(
406 "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n"
407 " this.channel = channel;\n"
408 "}\n"
409 "\n"
410 "private final com.google.protobuf.BlockingRpcChannel channel;\n");
411
412 for (int i = 0; i < descriptor_->method_count(); i++) {
413 const MethodDescriptor* method = descriptor_->method(i);
414 GenerateBlockingMethodSignature(printer, method);
415 printer->Print(" {\n");
416 printer->Indent();
417
418 map<string, string> vars;
419 vars["index"] = SimpleItoa(i);
420 vars["output"] = name_resolver_->GetImmutableClassName(
421 method->output_type());
422 printer->Print(vars,
423 "return ($output$) channel.callBlockingMethod(\n"
424 " getDescriptor().getMethods().get($index$),\n"
425 " controller,\n"
426 " request,\n"
427 " $output$.getDefaultInstance());\n");
428
429 printer->Outdent();
430 printer->Print(
431 "}\n"
432 "\n");
433 }
434
435 printer->Outdent();
436 printer->Print("}\n");
437 }
438
GenerateMethodSignature(io::Printer * printer,const MethodDescriptor * method,IsAbstract is_abstract)439 void ImmutableServiceGenerator::GenerateMethodSignature(io::Printer* printer,
440 const MethodDescriptor* method,
441 IsAbstract is_abstract) {
442 map<string, string> vars;
443 vars["name"] = UnderscoresToCamelCase(method);
444 vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
445 vars["output"] = name_resolver_->GetImmutableClassName(method->output_type());
446 vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : "";
447 printer->Print(vars,
448 "public $abstract$ void $name$(\n"
449 " com.google.protobuf.RpcController controller,\n"
450 " $input$ request,\n"
451 " com.google.protobuf.RpcCallback<$output$> done)");
452 }
453
GenerateBlockingMethodSignature(io::Printer * printer,const MethodDescriptor * method)454 void ImmutableServiceGenerator::GenerateBlockingMethodSignature(
455 io::Printer* printer,
456 const MethodDescriptor* method) {
457 map<string, string> vars;
458 vars["method"] = UnderscoresToCamelCase(method);
459 vars["input"] = name_resolver_->GetImmutableClassName(method->input_type());
460 vars["output"] = name_resolver_->GetImmutableClassName(method->output_type());
461 printer->Print(vars,
462 "\n"
463 "public $output$ $method$(\n"
464 " com.google.protobuf.RpcController controller,\n"
465 " $input$ request)\n"
466 " throws com.google.protobuf.ServiceException");
467 }
468
469 } // namespace java
470 } // namespace compiler
471 } // namespace protobuf
472 } // namespace google
473