• 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/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