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 44namespace google { 45namespace protobuf { 46namespace compiler { 47namespace java { 48 49ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor) 50 : descriptor_(descriptor) {} 51 52ServiceGenerator::~ServiceGenerator() {} 53 54// =================================================================== 55ImmutableServiceGenerator::ImmutableServiceGenerator( 56 const ServiceDescriptor* descriptor, Context* context) 57 : ServiceGenerator(descriptor), context_(context), 58 name_resolver_(context->GetNameResolver()) {} 59 60ImmutableServiceGenerator::~ImmutableServiceGenerator() {} 61 62void 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 112void 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 121void 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 129void 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 156void 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 177void 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 186void 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 234void 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 279void 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 323void 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 378void 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 439void 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 454void 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