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