// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. #include #include #include #include #include #include #include namespace google { namespace protobuf { namespace compiler { namespace java { ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor) : descriptor_(descriptor) {} ServiceGenerator::~ServiceGenerator() {} // =================================================================== ImmutableServiceGenerator::ImmutableServiceGenerator( const ServiceDescriptor* descriptor, Context* context) : ServiceGenerator(descriptor), context_(context), name_resolver_(context->GetNameResolver()) {} ImmutableServiceGenerator::~ImmutableServiceGenerator() {} void ImmutableServiceGenerator::Generate(io::Printer* printer) { bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true); WriteServiceDocComment(printer, descriptor_); MaybePrintGeneratedAnnotation(context_, printer, descriptor_, /* immutable = */ true); printer->Print( "public $static$ abstract class $classname$\n" " implements com.google.protobuf.Service {\n", "static", is_own_file ? "" : "static", "classname", descriptor_->name()); printer->Indent(); printer->Print("protected $classname$() {}\n\n", "classname", descriptor_->name()); GenerateInterface(printer); GenerateNewReflectiveServiceMethod(printer); GenerateNewReflectiveBlockingServiceMethod(printer); GenerateAbstractMethods(printer); // Generate getDescriptor() and getDescriptorForType(). printer->Print( "public static final\n" " com.google.protobuf.Descriptors.ServiceDescriptor\n" " getDescriptor() {\n" " return $file$.getDescriptor().getServices().get($index$);\n" "}\n", "file", name_resolver_->GetImmutableClassName(descriptor_->file()), "index", StrCat(descriptor_->index())); GenerateGetDescriptorForType(printer); // Generate more stuff. GenerateCallMethod(printer); GenerateGetPrototype(REQUEST, printer); GenerateGetPrototype(RESPONSE, printer); GenerateStub(printer); GenerateBlockingStub(printer); // Add an insertion point. printer->Print( "\n" "// @@protoc_insertion_point(class_scope:$full_name$)\n", "full_name", descriptor_->full_name()); printer->Outdent(); printer->Print("}\n\n"); } void ImmutableServiceGenerator::GenerateGetDescriptorForType( io::Printer* printer) { printer->Print( "public final com.google.protobuf.Descriptors.ServiceDescriptor\n" " getDescriptorForType() {\n" " return getDescriptor();\n" "}\n"); } void ImmutableServiceGenerator::GenerateInterface(io::Printer* printer) { printer->Print("public interface Interface {\n"); printer->Indent(); GenerateAbstractMethods(printer); printer->Outdent(); printer->Print("}\n\n"); } void ImmutableServiceGenerator::GenerateNewReflectiveServiceMethod( io::Printer* printer) { printer->Print( "public static com.google.protobuf.Service newReflectiveService(\n" " final Interface impl) {\n" " return new $classname$() {\n", "classname", descriptor_->name()); printer->Indent(); printer->Indent(); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); printer->Print("@java.lang.Override\n"); GenerateMethodSignature(printer, method, IS_CONCRETE); printer->Print( " {\n" " impl.$method$(controller, request, done);\n" "}\n\n", "method", UnderscoresToCamelCase(method)); } printer->Outdent(); printer->Print("};\n"); printer->Outdent(); printer->Print("}\n\n"); } void ImmutableServiceGenerator::GenerateNewReflectiveBlockingServiceMethod( io::Printer* printer) { printer->Print( "public static com.google.protobuf.BlockingService\n" " newReflectiveBlockingService(final BlockingInterface impl) {\n" " return new com.google.protobuf.BlockingService() {\n"); printer->Indent(); printer->Indent(); GenerateGetDescriptorForType(printer); GenerateCallBlockingMethod(printer); GenerateGetPrototype(REQUEST, printer); GenerateGetPrototype(RESPONSE, printer); printer->Outdent(); printer->Print("};\n"); printer->Outdent(); printer->Print("}\n\n"); } void ImmutableServiceGenerator::GenerateAbstractMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); WriteMethodDocComment(printer, method); GenerateMethodSignature(printer, method, IS_ABSTRACT); printer->Print(";\n\n"); } } std::string ImmutableServiceGenerator::GetOutput( const MethodDescriptor* method) { return name_resolver_->GetImmutableClassName(method->output_type()); } void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) { printer->Print( "\n" "public final void callMethod(\n" " com.google.protobuf.Descriptors.MethodDescriptor method,\n" " com.google.protobuf.RpcController controller,\n" " com.google.protobuf.Message request,\n" " com.google.protobuf.RpcCallback<\n" " com.google.protobuf.Message> done) {\n" " if (method.getService() != getDescriptor()) {\n" " throw new java.lang.IllegalArgumentException(\n" " \"Service.callMethod() given method descriptor for wrong \" +\n" " \"service type.\");\n" " }\n" " switch(method.getIndex()) {\n"); printer->Indent(); printer->Indent(); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); std::map vars; vars["index"] = StrCat(i); vars["method"] = UnderscoresToCamelCase(method); vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); vars["output"] = GetOutput(method); printer->Print( vars, "case $index$:\n" " this.$method$(controller, ($input$)request,\n" " com.google.protobuf.RpcUtil.<$output$>specializeCallback(\n" " done));\n" " return;\n"); } printer->Print( "default:\n" " throw new java.lang.AssertionError(\"Can't get here.\");\n"); printer->Outdent(); printer->Outdent(); printer->Print( " }\n" "}\n" "\n"); } void ImmutableServiceGenerator::GenerateCallBlockingMethod( io::Printer* printer) { printer->Print( "\n" "public final com.google.protobuf.Message callBlockingMethod(\n" " com.google.protobuf.Descriptors.MethodDescriptor method,\n" " com.google.protobuf.RpcController controller,\n" " com.google.protobuf.Message request)\n" " throws com.google.protobuf.ServiceException {\n" " if (method.getService() != getDescriptor()) {\n" " throw new java.lang.IllegalArgumentException(\n" " \"Service.callBlockingMethod() given method descriptor for \" +\n" " \"wrong service type.\");\n" " }\n" " switch(method.getIndex()) {\n"); printer->Indent(); printer->Indent(); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); std::map vars; vars["index"] = StrCat(i); vars["method"] = UnderscoresToCamelCase(method); vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); vars["output"] = GetOutput(method); printer->Print(vars, "case $index$:\n" " return impl.$method$(controller, ($input$)request);\n"); } printer->Print( "default:\n" " throw new java.lang.AssertionError(\"Can't get here.\");\n"); printer->Outdent(); printer->Outdent(); printer->Print( " }\n" "}\n" "\n"); } void ImmutableServiceGenerator::GenerateGetPrototype(RequestOrResponse which, io::Printer* printer) { /* * TODO(cpovirk): The exception message says "Service.foo" when it may be * "BlockingService.foo." Consider fixing. */ printer->Print( "public final com.google.protobuf.Message\n" " get$request_or_response$Prototype(\n" " com.google.protobuf.Descriptors.MethodDescriptor method) {\n" " if (method.getService() != getDescriptor()) {\n" " throw new java.lang.IllegalArgumentException(\n" " \"Service.get$request_or_response$Prototype() given method \" +\n" " \"descriptor for wrong service type.\");\n" " }\n" " switch(method.getIndex()) {\n", "request_or_response", (which == REQUEST) ? "Request" : "Response"); printer->Indent(); printer->Indent(); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); std::map vars; vars["index"] = StrCat(i); vars["type"] = (which == REQUEST) ? name_resolver_->GetImmutableClassName(method->input_type()) : GetOutput(method); printer->Print(vars, "case $index$:\n" " return $type$.getDefaultInstance();\n"); } printer->Print( "default:\n" " throw new java.lang.AssertionError(\"Can't get here.\");\n"); printer->Outdent(); printer->Outdent(); printer->Print( " }\n" "}\n" "\n"); } void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) { printer->Print( "public static Stub newStub(\n" " com.google.protobuf.RpcChannel channel) {\n" " return new Stub(channel);\n" "}\n" "\n" "public static final class Stub extends $classname$ implements Interface " "{" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Indent(); printer->Print( "private Stub(com.google.protobuf.RpcChannel channel) {\n" " this.channel = channel;\n" "}\n" "\n" "private final com.google.protobuf.RpcChannel channel;\n" "\n" "public com.google.protobuf.RpcChannel getChannel() {\n" " return channel;\n" "}\n"); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); printer->Print("\n"); GenerateMethodSignature(printer, method, IS_CONCRETE); printer->Print(" {\n"); printer->Indent(); std::map vars; vars["index"] = StrCat(i); vars["output"] = GetOutput(method); printer->Print(vars, "channel.callMethod(\n" " getDescriptor().getMethods().get($index$),\n" " controller,\n" " request,\n" " $output$.getDefaultInstance(),\n" " com.google.protobuf.RpcUtil.generalizeCallback(\n" " done,\n" " $output$.class,\n" " $output$.getDefaultInstance()));\n"); printer->Outdent(); printer->Print("}\n"); } printer->Outdent(); printer->Print( "}\n" "\n"); } void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) { printer->Print( "public static BlockingInterface newBlockingStub(\n" " com.google.protobuf.BlockingRpcChannel channel) {\n" " return new BlockingStub(channel);\n" "}\n" "\n"); printer->Print("public interface BlockingInterface {"); printer->Indent(); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); GenerateBlockingMethodSignature(printer, method); printer->Print(";\n"); } printer->Outdent(); printer->Print( "}\n" "\n"); printer->Print( "private static final class BlockingStub implements BlockingInterface " "{\n"); printer->Indent(); printer->Print( "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n" " this.channel = channel;\n" "}\n" "\n" "private final com.google.protobuf.BlockingRpcChannel channel;\n"); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); GenerateBlockingMethodSignature(printer, method); printer->Print(" {\n"); printer->Indent(); std::map vars; vars["index"] = StrCat(i); vars["output"] = GetOutput(method); printer->Print(vars, "return ($output$) channel.callBlockingMethod(\n" " getDescriptor().getMethods().get($index$),\n" " controller,\n" " request,\n" " $output$.getDefaultInstance());\n"); printer->Outdent(); printer->Print( "}\n" "\n"); } printer->Outdent(); printer->Print("}\n"); } void ImmutableServiceGenerator::GenerateMethodSignature( io::Printer* printer, const MethodDescriptor* method, IsAbstract is_abstract) { std::map vars; vars["name"] = UnderscoresToCamelCase(method); vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); vars["output"] = GetOutput(method); vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : ""; printer->Print(vars, "public $abstract$ void $name$(\n" " com.google.protobuf.RpcController controller,\n" " $input$ request,\n" " com.google.protobuf.RpcCallback<$output$> done)"); } void ImmutableServiceGenerator::GenerateBlockingMethodSignature( io::Printer* printer, const MethodDescriptor* method) { std::map vars; vars["method"] = UnderscoresToCamelCase(method); vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); vars["output"] = GetOutput(method); printer->Print(vars, "\n" "public $output$ $method$(\n" " com.google.protobuf.RpcController controller,\n" " $input$ request)\n" " throws com.google.protobuf.ServiceException"); } } // namespace java } // namespace compiler } // namespace protobuf } // namespace google