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