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/cpp/cpp_service.h> 36#include <google/protobuf/compiler/cpp/cpp_helpers.h> 37#include <google/protobuf/io/printer.h> 38#include <google/protobuf/stubs/strutil.h> 39 40namespace google { 41namespace protobuf { 42namespace compiler { 43namespace cpp { 44 45ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor, 46 const string& dllexport_decl) 47 : descriptor_(descriptor) { 48 vars_["classname"] = descriptor_->name(); 49 vars_["full_name"] = descriptor_->full_name(); 50 if (dllexport_decl.empty()) { 51 vars_["dllexport"] = ""; 52 } else { 53 vars_["dllexport"] = dllexport_decl + " "; 54 } 55} 56 57ServiceGenerator::~ServiceGenerator() {} 58 59void ServiceGenerator::GenerateDeclarations(io::Printer* printer) { 60 // Forward-declare the stub type. 61 printer->Print(vars_, 62 "class $classname$_Stub;\n" 63 "\n"); 64 65 GenerateInterface(printer); 66 GenerateStubDefinition(printer); 67} 68 69void ServiceGenerator::GenerateInterface(io::Printer* printer) { 70 printer->Print(vars_, 71 "class $dllexport$$classname$ : public ::google::protobuf::Service {\n" 72 " protected:\n" 73 " // This class should be treated as an abstract interface.\n" 74 " inline $classname$() {};\n" 75 " public:\n" 76 " virtual ~$classname$();\n"); 77 printer->Indent(); 78 79 printer->Print(vars_, 80 "\n" 81 "typedef $classname$_Stub Stub;\n" 82 "\n" 83 "static const ::google::protobuf::ServiceDescriptor* descriptor();\n" 84 "\n"); 85 86 GenerateMethodSignatures(VIRTUAL, printer); 87 88 printer->Print( 89 "\n" 90 "// implements Service ----------------------------------------------\n" 91 "\n" 92 "const ::google::protobuf::ServiceDescriptor* GetDescriptor();\n" 93 "void CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" 94 " ::google::protobuf::RpcController* controller,\n" 95 " const ::google::protobuf::Message* request,\n" 96 " ::google::protobuf::Message* response,\n" 97 " ::google::protobuf::Closure* done);\n" 98 "const ::google::protobuf::Message& GetRequestPrototype(\n" 99 " const ::google::protobuf::MethodDescriptor* method) const;\n" 100 "const ::google::protobuf::Message& GetResponsePrototype(\n" 101 " const ::google::protobuf::MethodDescriptor* method) const;\n"); 102 103 printer->Outdent(); 104 printer->Print(vars_, 105 "\n" 106 " private:\n" 107 " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n" 108 "};\n" 109 "\n"); 110} 111 112void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) { 113 printer->Print(vars_, 114 "class $dllexport$$classname$_Stub : public $classname$ {\n" 115 " public:\n"); 116 117 printer->Indent(); 118 119 printer->Print(vars_, 120 "$classname$_Stub(::google::protobuf::RpcChannel* channel);\n" 121 "$classname$_Stub(::google::protobuf::RpcChannel* channel,\n" 122 " ::google::protobuf::Service::ChannelOwnership ownership);\n" 123 "~$classname$_Stub();\n" 124 "\n" 125 "inline ::google::protobuf::RpcChannel* channel() { return channel_; }\n" 126 "\n" 127 "// implements $classname$ ------------------------------------------\n" 128 "\n"); 129 130 GenerateMethodSignatures(NON_VIRTUAL, printer); 131 132 printer->Outdent(); 133 printer->Print(vars_, 134 " private:\n" 135 " ::google::protobuf::RpcChannel* channel_;\n" 136 " bool owns_channel_;\n" 137 " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n" 138 "};\n" 139 "\n"); 140} 141 142void ServiceGenerator::GenerateMethodSignatures( 143 VirtualOrNon virtual_or_non, io::Printer* printer) { 144 for (int i = 0; i < descriptor_->method_count(); i++) { 145 const MethodDescriptor* method = descriptor_->method(i); 146 map<string, string> sub_vars; 147 sub_vars["name"] = method->name(); 148 sub_vars["input_type"] = ClassName(method->input_type(), true); 149 sub_vars["output_type"] = ClassName(method->output_type(), true); 150 sub_vars["virtual"] = virtual_or_non == VIRTUAL ? "virtual " : ""; 151 152 printer->Print(sub_vars, 153 "$virtual$void $name$(::google::protobuf::RpcController* controller,\n" 154 " const $input_type$* request,\n" 155 " $output_type$* response,\n" 156 " ::google::protobuf::Closure* done);\n"); 157 } 158} 159 160// =================================================================== 161 162void ServiceGenerator::GenerateDescriptorInitializer( 163 io::Printer* printer, int index) { 164 map<string, string> vars; 165 vars["classname"] = descriptor_->name(); 166 vars["index"] = SimpleItoa(index); 167 168 printer->Print(vars, 169 "$classname$_descriptor_ = file->service($index$);\n"); 170} 171 172// =================================================================== 173 174void ServiceGenerator::GenerateImplementation(io::Printer* printer) { 175 printer->Print(vars_, 176 "$classname$::~$classname$() {}\n" 177 "\n" 178 "const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n" 179 " protobuf_AssignDescriptorsOnce();\n" 180 " return $classname$_descriptor_;\n" 181 "}\n" 182 "\n" 183 "const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n" 184 " protobuf_AssignDescriptorsOnce();\n" 185 " return $classname$_descriptor_;\n" 186 "}\n" 187 "\n"); 188 189 // Generate methods of the interface. 190 GenerateNotImplementedMethods(printer); 191 GenerateCallMethod(printer); 192 GenerateGetPrototype(REQUEST, printer); 193 GenerateGetPrototype(RESPONSE, printer); 194 195 // Generate stub implementation. 196 printer->Print(vars_, 197 "$classname$_Stub::$classname$_Stub(::google::protobuf::RpcChannel* channel)\n" 198 " : channel_(channel), owns_channel_(false) {}\n" 199 "$classname$_Stub::$classname$_Stub(\n" 200 " ::google::protobuf::RpcChannel* channel,\n" 201 " ::google::protobuf::Service::ChannelOwnership ownership)\n" 202 " : channel_(channel),\n" 203 " owns_channel_(ownership == ::google::protobuf::Service::STUB_OWNS_CHANNEL) {}\n" 204 "$classname$_Stub::~$classname$_Stub() {\n" 205 " if (owns_channel_) delete channel_;\n" 206 "}\n" 207 "\n"); 208 209 GenerateStubMethods(printer); 210} 211 212void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) { 213 for (int i = 0; i < descriptor_->method_count(); i++) { 214 const MethodDescriptor* method = descriptor_->method(i); 215 map<string, string> sub_vars; 216 sub_vars["classname"] = descriptor_->name(); 217 sub_vars["name"] = method->name(); 218 sub_vars["index"] = SimpleItoa(i); 219 sub_vars["input_type"] = ClassName(method->input_type(), true); 220 sub_vars["output_type"] = ClassName(method->output_type(), true); 221 222 printer->Print(sub_vars, 223 "void $classname$::$name$(::google::protobuf::RpcController* controller,\n" 224 " const $input_type$*,\n" 225 " $output_type$*,\n" 226 " ::google::protobuf::Closure* done) {\n" 227 " controller->SetFailed(\"Method $name$() not implemented.\");\n" 228 " done->Run();\n" 229 "}\n" 230 "\n"); 231 } 232} 233 234void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { 235 printer->Print(vars_, 236 "void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" 237 " ::google::protobuf::RpcController* controller,\n" 238 " const ::google::protobuf::Message* request,\n" 239 " ::google::protobuf::Message* response,\n" 240 " ::google::protobuf::Closure* done) {\n" 241 " GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n" 242 " switch(method->index()) {\n"); 243 244 for (int i = 0; i < descriptor_->method_count(); i++) { 245 const MethodDescriptor* method = descriptor_->method(i); 246 map<string, string> sub_vars; 247 sub_vars["name"] = method->name(); 248 sub_vars["index"] = SimpleItoa(i); 249 sub_vars["input_type"] = ClassName(method->input_type(), true); 250 sub_vars["output_type"] = ClassName(method->output_type(), true); 251 252 // Note: down_cast does not work here because it only works on pointers, 253 // not references. 254 printer->Print(sub_vars, 255 " case $index$:\n" 256 " $name$(controller,\n" 257 " ::google::protobuf::down_cast<const $input_type$*>(request),\n" 258 " ::google::protobuf::down_cast< $output_type$*>(response),\n" 259 " done);\n" 260 " break;\n"); 261 } 262 263 printer->Print(vars_, 264 " default:\n" 265 " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" 266 " break;\n" 267 " }\n" 268 "}\n" 269 "\n"); 270} 271 272void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, 273 io::Printer* printer) { 274 if (which == REQUEST) { 275 printer->Print(vars_, 276 "const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n"); 277 } else { 278 printer->Print(vars_, 279 "const ::google::protobuf::Message& $classname$::GetResponsePrototype(\n"); 280 } 281 282 printer->Print(vars_, 283 " const ::google::protobuf::MethodDescriptor* method) const {\n" 284 " GOOGLE_DCHECK_EQ(method->service(), descriptor());\n" 285 " switch(method->index()) {\n"); 286 287 for (int i = 0; i < descriptor_->method_count(); i++) { 288 const MethodDescriptor* method = descriptor_->method(i); 289 const Descriptor* type = 290 (which == REQUEST) ? method->input_type() : method->output_type(); 291 292 map<string, string> sub_vars; 293 sub_vars["index"] = SimpleItoa(i); 294 sub_vars["type"] = ClassName(type, true); 295 296 printer->Print(sub_vars, 297 " case $index$:\n" 298 " return $type$::default_instance();\n"); 299 } 300 301 printer->Print(vars_, 302 " default:\n" 303 " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" 304 " return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n" 305 " }\n" 306 "}\n" 307 "\n"); 308} 309 310void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { 311 for (int i = 0; i < descriptor_->method_count(); i++) { 312 const MethodDescriptor* method = descriptor_->method(i); 313 map<string, string> sub_vars; 314 sub_vars["classname"] = descriptor_->name(); 315 sub_vars["name"] = method->name(); 316 sub_vars["index"] = SimpleItoa(i); 317 sub_vars["input_type"] = ClassName(method->input_type(), true); 318 sub_vars["output_type"] = ClassName(method->output_type(), true); 319 320 printer->Print(sub_vars, 321 "void $classname$_Stub::$name$(::google::protobuf::RpcController* controller,\n" 322 " const $input_type$* request,\n" 323 " $output_type$* response,\n" 324 " ::google::protobuf::Closure* done) {\n" 325 " channel_->CallMethod(descriptor()->method($index$),\n" 326 " controller, request, response, done);\n" 327 "}\n"); 328 } 329} 330 331} // namespace cpp 332} // namespace compiler 333} // namespace protobuf 334} // namespace google 335