• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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