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