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/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
40 namespace google {
41 namespace protobuf {
42 namespace compiler {
43 namespace cpp {
44
ServiceGenerator(const ServiceDescriptor * descriptor,const Options & options)45 ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
46 const Options& options)
47 : descriptor_(descriptor) {
48 vars_["classname"] = descriptor_->name();
49 vars_["full_name"] = descriptor_->full_name();
50 if (options.dllexport_decl.empty()) {
51 vars_["dllexport"] = "";
52 } else {
53 vars_["dllexport"] = options.dllexport_decl + " ";
54 }
55 }
56
~ServiceGenerator()57 ServiceGenerator::~ServiceGenerator() {}
58
GenerateDeclarations(io::Printer * printer)59 void 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
GenerateInterface(io::Printer * printer)69 void 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
GenerateStubDefinition(io::Printer * printer)112 void 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
GenerateMethodSignatures(VirtualOrNon virtual_or_non,io::Printer * printer)142 void 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
GenerateDescriptorInitializer(io::Printer * printer,int index)162 void 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
GenerateImplementation(io::Printer * printer)174 void 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
GenerateNotImplementedMethods(io::Printer * printer)212 void 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
GenerateCallMethod(io::Printer * printer)234 void 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
GenerateGetPrototype(RequestOrResponse which,io::Printer * printer)272 void 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 *static_cast< ::google::protobuf::Message*>(NULL);\n"
305 " }\n"
306 "}\n"
307 "\n");
308 }
309
GenerateStubMethods(io::Printer * printer)310 void 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