blob: 1ae4f461663b75c6cf1333c170123d8d91dfd843 [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
temporal40ee5512008-07-10 02:12:20 +00003// http://code.google.com/p/protobuf/
4//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
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
41namespace google {
42namespace protobuf {
43namespace compiler {
44namespace java {
45
46ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor)
47 : descriptor_(descriptor) {}
48
49ServiceGenerator::~ServiceGenerator() {}
50
51void 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
kenton@google.comd37d46d2009-04-25 02:53:47 +000060 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);
temporal40ee5512008-07-10 02:12:20 +000070
71 // Generate getDescriptor() and getDescriptorForType().
72 printer->Print(
temporal40ee5512008-07-10 02:12:20 +000073 "public static final\n"
74 " com.google.protobuf.Descriptors.ServiceDescriptor\n"
75 " getDescriptor() {\n"
76 " return $file$.getDescriptor().getServices().get($index$);\n"
temporal40ee5512008-07-10 02:12:20 +000077 "}\n",
78 "file", ClassName(descriptor_->file()),
79 "index", SimpleItoa(descriptor_->index()));
kenton@google.comd37d46d2009-04-25 02:53:47 +000080 GenerateGetDescriptorForType(printer);
temporal40ee5512008-07-10 02:12:20 +000081
82 // Generate more stuff.
83 GenerateCallMethod(printer);
84 GenerateGetPrototype(REQUEST, printer);
85 GenerateGetPrototype(RESPONSE, printer);
86 GenerateStub(printer);
kenton@google.comd37d46d2009-04-25 02:53:47 +000087 GenerateBlockingStub(printer);
temporal40ee5512008-07-10 02:12:20 +000088
89 printer->Outdent();
90 printer->Print("}\n\n");
91}
92
kenton@google.comd37d46d2009-04-25 02:53:47 +000093void 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
101void 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
109void 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);
liujisi@google.com33165fe2010-11-02 13:14:58 +0000121 printer->Print("@java.lang.Override\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +0000122 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
136void 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
157void 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
temporal40ee5512008-07-10 02:12:20 +0000165void 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"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000200 " 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
211void 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");
temporal40ee5512008-07-10 02:12:20 +0000243
244 printer->Outdent();
245 printer->Outdent();
246
247 printer->Print(
248 " }\n"
249 "}\n"
250 "\n");
251}
252
253void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
254 io::Printer* printer) {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000255 /*
256 * TODO(cpovirk): The exception message says "Service.foo" when it may be
257 * "BlockingService.foo." Consider fixing.
258 */
temporal40ee5512008-07-10 02:12:20 +0000259 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"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000286 " throw new java.lang.AssertionError(\"Can't get here.\");\n");
temporal40ee5512008-07-10 02:12:20 +0000287
288 printer->Outdent();
289 printer->Outdent();
290
291 printer->Print(
292 " }\n"
293 "}\n"
294 "\n");
295}
296
297void 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"
kenton@google.comd37d46d2009-04-25 02:53:47 +0000304 "public static final class Stub extends $classname$ implements Interface {"
305 "\n",
temporal40ee5512008-07-10 02:12:20 +0000306 "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);
kenton@google.comd37d46d2009-04-25 02:53:47 +0000322 printer->Print("\n");
323 GenerateMethodSignature(printer, method, IS_CONCRETE);
324 printer->Print(" {\n");
325 printer->Indent();
326
temporal40ee5512008-07-10 02:12:20 +0000327 map<string, string> vars;
328 vars["index"] = SimpleItoa(i);
temporal40ee5512008-07-10 02:12:20 +0000329 vars["output"] = ClassName(method->output_type());
330 printer->Print(vars,
kenton@google.comd37d46d2009-04-25 02:53:47 +0000331 "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
351void 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");
temporal40ee5512008-07-10 02:12:20 +0000405 }
406
407 printer->Outdent();
408 printer->Print("}\n");
409}
410
kenton@google.comd37d46d2009-04-25 02:53:47 +0000411void 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
426void 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
temporal40ee5512008-07-10 02:12:20 +0000441} // namespace java
442} // namespace compiler
443} // namespace protobuf
444} // namespace google