• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
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 #include <google/protobuf/compiler/java/java_helpers.h>
37 #include <google/protobuf/io/printer.h>
38 #include <google/protobuf/descriptor.pb.h>
39 #include <google/protobuf/stubs/strutil.h>
40 
41 namespace google {
42 namespace protobuf {
43 namespace compiler {
44 namespace java {
45 
ServiceGenerator(const ServiceDescriptor * descriptor)46 ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor)
47   : descriptor_(descriptor) {}
48 
~ServiceGenerator()49 ServiceGenerator::~ServiceGenerator() {}
50 
Generate(io::Printer * printer)51 void ServiceGenerator::Generate(io::Printer* printer) {
52   bool is_own_file = descriptor_->file()->options().java_multiple_files();
53   printer->Print(
54     "public $static$ abstract class $classname$\n"
55     "    implements com.google.protobuf.Service {\n",
56     "static", is_own_file ? "" : "static",
57     "classname", descriptor_->name());
58   printer->Indent();
59 
60   printer->Print(
61     "protected $classname$() {}\n\n",
62     "classname", descriptor_->name());
63 
64   GenerateInterface(printer);
65 
66   GenerateNewReflectiveServiceMethod(printer);
67   GenerateNewReflectiveBlockingServiceMethod(printer);
68 
69   GenerateAbstractMethods(printer);
70 
71   // Generate getDescriptor() and getDescriptorForType().
72   printer->Print(
73     "public static final\n"
74     "    com.google.protobuf.Descriptors.ServiceDescriptor\n"
75     "    getDescriptor() {\n"
76     "  return $file$.getDescriptor().getServices().get($index$);\n"
77     "}\n",
78     "file", ClassName(descriptor_->file()),
79     "index", SimpleItoa(descriptor_->index()));
80   GenerateGetDescriptorForType(printer);
81 
82   // Generate more stuff.
83   GenerateCallMethod(printer);
84   GenerateGetPrototype(REQUEST, printer);
85   GenerateGetPrototype(RESPONSE, printer);
86   GenerateStub(printer);
87   GenerateBlockingStub(printer);
88 
89   printer->Outdent();
90   printer->Print("}\n\n");
91 }
92 
GenerateGetDescriptorForType(io::Printer * printer)93 void ServiceGenerator::GenerateGetDescriptorForType(io::Printer* printer) {
94   printer->Print(
95     "public final com.google.protobuf.Descriptors.ServiceDescriptor\n"
96     "    getDescriptorForType() {\n"
97     "  return getDescriptor();\n"
98     "}\n");
99 }
100 
GenerateInterface(io::Printer * printer)101 void ServiceGenerator::GenerateInterface(io::Printer* printer) {
102   printer->Print("public interface Interface {\n");
103   printer->Indent();
104   GenerateAbstractMethods(printer);
105   printer->Outdent();
106   printer->Print("}\n\n");
107 }
108 
GenerateNewReflectiveServiceMethod(io::Printer * printer)109 void ServiceGenerator::GenerateNewReflectiveServiceMethod(
110     io::Printer* printer) {
111   printer->Print(
112     "public static com.google.protobuf.Service newReflectiveService(\n"
113     "    final Interface impl) {\n"
114     "  return new $classname$() {\n",
115     "classname", descriptor_->name());
116   printer->Indent();
117   printer->Indent();
118 
119   for (int i = 0; i < descriptor_->method_count(); i++) {
120     const MethodDescriptor* method = descriptor_->method(i);
121     printer->Print("@Override\n");
122     GenerateMethodSignature(printer, method, IS_CONCRETE);
123     printer->Print(
124       " {\n"
125       "  impl.$method$(controller, request, done);\n"
126       "}\n\n",
127       "method", UnderscoresToCamelCase(method));
128   }
129 
130   printer->Outdent();
131   printer->Print("};\n");
132   printer->Outdent();
133   printer->Print("}\n\n");
134 }
135 
GenerateNewReflectiveBlockingServiceMethod(io::Printer * printer)136 void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
137     io::Printer* printer) {
138   printer->Print(
139     "public static com.google.protobuf.BlockingService\n"
140     "    newReflectiveBlockingService(final BlockingInterface impl) {\n"
141     "  return new com.google.protobuf.BlockingService() {\n");
142   printer->Indent();
143   printer->Indent();
144 
145   GenerateGetDescriptorForType(printer);
146 
147   GenerateCallBlockingMethod(printer);
148   GenerateGetPrototype(REQUEST, printer);
149   GenerateGetPrototype(RESPONSE, printer);
150 
151   printer->Outdent();
152   printer->Print("};\n");
153   printer->Outdent();
154   printer->Print("}\n\n");
155 }
156 
GenerateAbstractMethods(io::Printer * printer)157 void ServiceGenerator::GenerateAbstractMethods(io::Printer* printer) {
158   for (int i = 0; i < descriptor_->method_count(); i++) {
159     const MethodDescriptor* method = descriptor_->method(i);
160     GenerateMethodSignature(printer, method, IS_ABSTRACT);
161     printer->Print(";\n\n");
162   }
163 }
164 
GenerateCallMethod(io::Printer * printer)165 void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
166   printer->Print(
167     "\n"
168     "public final void callMethod(\n"
169     "    com.google.protobuf.Descriptors.MethodDescriptor method,\n"
170     "    com.google.protobuf.RpcController controller,\n"
171     "    com.google.protobuf.Message request,\n"
172     "    com.google.protobuf.RpcCallback<\n"
173     "      com.google.protobuf.Message> done) {\n"
174     "  if (method.getService() != getDescriptor()) {\n"
175     "    throw new java.lang.IllegalArgumentException(\n"
176     "      \"Service.callMethod() given method descriptor for wrong \" +\n"
177     "      \"service type.\");\n"
178     "  }\n"
179     "  switch(method.getIndex()) {\n");
180   printer->Indent();
181   printer->Indent();
182 
183   for (int i = 0; i < descriptor_->method_count(); i++) {
184     const MethodDescriptor* method = descriptor_->method(i);
185     map<string, string> vars;
186     vars["index"] = SimpleItoa(i);
187     vars["method"] = UnderscoresToCamelCase(method);
188     vars["input"] = ClassName(method->input_type());
189     vars["output"] = ClassName(method->output_type());
190     printer->Print(vars,
191       "case $index$:\n"
192       "  this.$method$(controller, ($input$)request,\n"
193       "    com.google.protobuf.RpcUtil.<$output$>specializeCallback(\n"
194       "      done));\n"
195       "  return;\n");
196   }
197 
198   printer->Print(
199     "default:\n"
200     "  throw new java.lang.AssertionError(\"Can't get here.\");\n");
201 
202   printer->Outdent();
203   printer->Outdent();
204 
205   printer->Print(
206     "  }\n"
207     "}\n"
208     "\n");
209 }
210 
GenerateCallBlockingMethod(io::Printer * printer)211 void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) {
212   printer->Print(
213     "\n"
214     "public final com.google.protobuf.Message callBlockingMethod(\n"
215     "    com.google.protobuf.Descriptors.MethodDescriptor method,\n"
216     "    com.google.protobuf.RpcController controller,\n"
217     "    com.google.protobuf.Message request)\n"
218     "    throws com.google.protobuf.ServiceException {\n"
219     "  if (method.getService() != getDescriptor()) {\n"
220     "    throw new java.lang.IllegalArgumentException(\n"
221     "      \"Service.callBlockingMethod() given method descriptor for \" +\n"
222     "      \"wrong service type.\");\n"
223     "  }\n"
224     "  switch(method.getIndex()) {\n");
225   printer->Indent();
226   printer->Indent();
227 
228   for (int i = 0; i < descriptor_->method_count(); i++) {
229     const MethodDescriptor* method = descriptor_->method(i);
230     map<string, string> vars;
231     vars["index"] = SimpleItoa(i);
232     vars["method"] = UnderscoresToCamelCase(method);
233     vars["input"] = ClassName(method->input_type());
234     vars["output"] = ClassName(method->output_type());
235     printer->Print(vars,
236       "case $index$:\n"
237       "  return impl.$method$(controller, ($input$)request);\n");
238   }
239 
240   printer->Print(
241     "default:\n"
242     "  throw new java.lang.AssertionError(\"Can't get here.\");\n");
243 
244   printer->Outdent();
245   printer->Outdent();
246 
247   printer->Print(
248     "  }\n"
249     "}\n"
250     "\n");
251 }
252 
GenerateGetPrototype(RequestOrResponse which,io::Printer * printer)253 void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
254                                             io::Printer* printer) {
255   /*
256    * TODO(cpovirk): The exception message says "Service.foo" when it may be
257    * "BlockingService.foo."  Consider fixing.
258    */
259   printer->Print(
260     "public final com.google.protobuf.Message\n"
261     "    get$request_or_response$Prototype(\n"
262     "    com.google.protobuf.Descriptors.MethodDescriptor method) {\n"
263     "  if (method.getService() != getDescriptor()) {\n"
264     "    throw new java.lang.IllegalArgumentException(\n"
265     "      \"Service.get$request_or_response$Prototype() given method \" +\n"
266     "      \"descriptor for wrong service type.\");\n"
267     "  }\n"
268     "  switch(method.getIndex()) {\n",
269     "request_or_response", (which == REQUEST) ? "Request" : "Response");
270   printer->Indent();
271   printer->Indent();
272 
273   for (int i = 0; i < descriptor_->method_count(); i++) {
274     const MethodDescriptor* method = descriptor_->method(i);
275     map<string, string> vars;
276     vars["index"] = SimpleItoa(i);
277     vars["type"] = ClassName(
278       (which == REQUEST) ? method->input_type() : method->output_type());
279     printer->Print(vars,
280       "case $index$:\n"
281       "  return $type$.getDefaultInstance();\n");
282   }
283 
284   printer->Print(
285     "default:\n"
286     "  throw new java.lang.AssertionError(\"Can't get here.\");\n");
287 
288   printer->Outdent();
289   printer->Outdent();
290 
291   printer->Print(
292     "  }\n"
293     "}\n"
294     "\n");
295 }
296 
GenerateStub(io::Printer * printer)297 void ServiceGenerator::GenerateStub(io::Printer* printer) {
298   printer->Print(
299     "public static Stub newStub(\n"
300     "    com.google.protobuf.RpcChannel channel) {\n"
301     "  return new Stub(channel);\n"
302     "}\n"
303     "\n"
304     "public static final class Stub extends $classname$ implements Interface {"
305     "\n",
306     "classname", ClassName(descriptor_));
307   printer->Indent();
308 
309   printer->Print(
310     "private Stub(com.google.protobuf.RpcChannel channel) {\n"
311     "  this.channel = channel;\n"
312     "}\n"
313     "\n"
314     "private final com.google.protobuf.RpcChannel channel;\n"
315     "\n"
316     "public com.google.protobuf.RpcChannel getChannel() {\n"
317     "  return channel;\n"
318     "}\n");
319 
320   for (int i = 0; i < descriptor_->method_count(); i++) {
321     const MethodDescriptor* method = descriptor_->method(i);
322     printer->Print("\n");
323     GenerateMethodSignature(printer, method, IS_CONCRETE);
324     printer->Print(" {\n");
325     printer->Indent();
326 
327     map<string, string> vars;
328     vars["index"] = SimpleItoa(i);
329     vars["output"] = ClassName(method->output_type());
330     printer->Print(vars,
331       "channel.callMethod(\n"
332       "  getDescriptor().getMethods().get($index$),\n"
333       "  controller,\n"
334       "  request,\n"
335       "  $output$.getDefaultInstance(),\n"
336       "  com.google.protobuf.RpcUtil.generalizeCallback(\n"
337       "    done,\n"
338       "    $output$.class,\n"
339       "    $output$.getDefaultInstance()));\n");
340 
341     printer->Outdent();
342     printer->Print("}\n");
343   }
344 
345   printer->Outdent();
346   printer->Print(
347     "}\n"
348     "\n");
349 }
350 
GenerateBlockingStub(io::Printer * printer)351 void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
352   printer->Print(
353     "public static BlockingInterface newBlockingStub(\n"
354     "    com.google.protobuf.BlockingRpcChannel channel) {\n"
355     "  return new BlockingStub(channel);\n"
356     "}\n"
357     "\n");
358 
359   printer->Print(
360     "public interface BlockingInterface {");
361   printer->Indent();
362 
363   for (int i = 0; i < descriptor_->method_count(); i++) {
364     const MethodDescriptor* method = descriptor_->method(i);
365     GenerateBlockingMethodSignature(printer, method);
366     printer->Print(";\n");
367   }
368 
369   printer->Outdent();
370   printer->Print(
371     "}\n"
372     "\n");
373 
374   printer->Print(
375     "private static final class BlockingStub implements BlockingInterface {\n");
376   printer->Indent();
377 
378   printer->Print(
379     "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n"
380     "  this.channel = channel;\n"
381     "}\n"
382     "\n"
383     "private final com.google.protobuf.BlockingRpcChannel channel;\n");
384 
385   for (int i = 0; i < descriptor_->method_count(); i++) {
386     const MethodDescriptor* method = descriptor_->method(i);
387     GenerateBlockingMethodSignature(printer, method);
388     printer->Print(" {\n");
389     printer->Indent();
390 
391     map<string, string> vars;
392     vars["index"] = SimpleItoa(i);
393     vars["output"] = ClassName(method->output_type());
394     printer->Print(vars,
395       "return ($output$) channel.callBlockingMethod(\n"
396       "  getDescriptor().getMethods().get($index$),\n"
397       "  controller,\n"
398       "  request,\n"
399       "  $output$.getDefaultInstance());\n");
400 
401     printer->Outdent();
402     printer->Print(
403       "}\n"
404       "\n");
405   }
406 
407   printer->Outdent();
408   printer->Print("}\n");
409 }
410 
GenerateMethodSignature(io::Printer * printer,const MethodDescriptor * method,IsAbstract is_abstract)411 void ServiceGenerator::GenerateMethodSignature(io::Printer* printer,
412                                                const MethodDescriptor* method,
413                                                IsAbstract is_abstract) {
414   map<string, string> vars;
415   vars["name"] = UnderscoresToCamelCase(method);
416   vars["input"] = ClassName(method->input_type());
417   vars["output"] = ClassName(method->output_type());
418   vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : "";
419   printer->Print(vars,
420     "public $abstract$ void $name$(\n"
421     "    com.google.protobuf.RpcController controller,\n"
422     "    $input$ request,\n"
423     "    com.google.protobuf.RpcCallback<$output$> done)");
424 }
425 
GenerateBlockingMethodSignature(io::Printer * printer,const MethodDescriptor * method)426 void ServiceGenerator::GenerateBlockingMethodSignature(
427     io::Printer* printer,
428     const MethodDescriptor* method) {
429   map<string, string> vars;
430   vars["method"] = UnderscoresToCamelCase(method);
431   vars["input"] = ClassName(method->input_type());
432   vars["output"] = ClassName(method->output_type());
433   printer->Print(vars,
434     "\n"
435     "public $output$ $method$(\n"
436     "    com.google.protobuf.RpcController controller,\n"
437     "    $input$ request)\n"
438     "    throws com.google.protobuf.ServiceException");
439 }
440 
441 }  // namespace java
442 }  // namespace compiler
443 }  // namespace protobuf
444 }  // namespace google
445