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 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 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 93void 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); 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 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 165void 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 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"); 243 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) { 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 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" 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 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"); 405 } 406 407 printer->Outdent(); 408 printer->Print("}\n"); 409} 410 411void 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 441} // namespace java 442} // namespace compiler 443} // namespace protobuf 444} // namespace google 445