Line data Source code
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 :
45 21 : ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
46 : const Options& options)
47 21 : : descriptor_(descriptor) {
48 63 : vars_["classname"] = descriptor_->name();
49 63 : vars_["full_name"] = descriptor_->full_name();
50 42 : if (options.dllexport_decl.empty()) {
51 42 : vars_["dllexport"] = "";
52 : } else {
53 0 : vars_["dllexport"] = options.dllexport_decl + " ";
54 : }
55 21 : }
56 :
57 42 : ServiceGenerator::~ServiceGenerator() {}
58 :
59 4 : void ServiceGenerator::GenerateDeclarations(io::Printer* printer) {
60 : // Forward-declare the stub type.
61 : printer->Print(vars_,
62 : "class $classname$_Stub;\n"
63 4 : "\n");
64 :
65 4 : GenerateInterface(printer);
66 4 : GenerateStubDefinition(printer);
67 4 : }
68 :
69 4 : 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 4 : " virtual ~$classname$();\n");
77 4 : 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 4 : "\n");
85 :
86 4 : 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 4 : " const ::google::protobuf::MethodDescriptor* method) const;\n");
102 :
103 4 : printer->Outdent();
104 : printer->Print(vars_,
105 : "\n"
106 : " private:\n"
107 : " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n"
108 : "};\n"
109 4 : "\n");
110 4 : }
111 :
112 4 : void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) {
113 : printer->Print(vars_,
114 : "class $dllexport$$classname$_Stub : public $classname$ {\n"
115 4 : " public:\n");
116 :
117 4 : 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 4 : "\n");
129 :
130 4 : GenerateMethodSignatures(NON_VIRTUAL, printer);
131 :
132 4 : 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 4 : "\n");
140 4 : }
141 :
142 8 : void ServiceGenerator::GenerateMethodSignatures(
143 : VirtualOrNon virtual_or_non, io::Printer* printer) {
144 36 : for (int i = 0; i < descriptor_->method_count(); i++) {
145 68 : const MethodDescriptor* method = descriptor_->method(i);
146 : map<string, string> sub_vars;
147 20 : sub_vars["name"] = method->name();
148 30 : sub_vars["input_type"] = ClassName(method->input_type(), true);
149 30 : sub_vars["output_type"] = ClassName(method->output_type(), true);
150 20 : 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 10 : " ::google::protobuf::Closure* done);\n");
157 : }
158 8 : }
159 :
160 : // ===================================================================
161 :
162 4 : void ServiceGenerator::GenerateDescriptorInitializer(
163 : io::Printer* printer, int index) {
164 : map<string, string> vars;
165 8 : vars["classname"] = descriptor_->name();
166 12 : vars["index"] = SimpleItoa(index);
167 :
168 : printer->Print(vars,
169 4 : "$classname$_descriptor_ = file->service($index$);\n");
170 4 : }
171 :
172 : // ===================================================================
173 :
174 4 : 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 4 : "\n");
188 :
189 : // Generate methods of the interface.
190 4 : GenerateNotImplementedMethods(printer);
191 4 : GenerateCallMethod(printer);
192 4 : GenerateGetPrototype(REQUEST, printer);
193 4 : 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 4 : "\n");
208 :
209 4 : GenerateStubMethods(printer);
210 4 : }
211 :
212 4 : void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) {
213 18 : for (int i = 0; i < descriptor_->method_count(); i++) {
214 39 : const MethodDescriptor* method = descriptor_->method(i);
215 : map<string, string> sub_vars;
216 10 : sub_vars["classname"] = descriptor_->name();
217 10 : sub_vars["name"] = method->name();
218 15 : sub_vars["index"] = SimpleItoa(i);
219 15 : sub_vars["input_type"] = ClassName(method->input_type(), true);
220 15 : 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 5 : "\n");
231 : }
232 4 : }
233 :
234 4 : 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 4 : " switch(method->index()) {\n");
243 :
244 18 : for (int i = 0; i < descriptor_->method_count(); i++) {
245 34 : const MethodDescriptor* method = descriptor_->method(i);
246 : map<string, string> sub_vars;
247 10 : sub_vars["name"] = method->name();
248 15 : sub_vars["index"] = SimpleItoa(i);
249 15 : sub_vars["input_type"] = ClassName(method->input_type(), true);
250 15 : 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 5 : " 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 4 : "\n");
270 4 : }
271 :
272 8 : void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
273 : io::Printer* printer) {
274 8 : if (which == REQUEST) {
275 : printer->Print(vars_,
276 4 : "const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n");
277 : } else {
278 : printer->Print(vars_,
279 4 : "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 8 : " switch(method->index()) {\n");
286 :
287 36 : for (int i = 0; i < descriptor_->method_count(); i++) {
288 48 : const MethodDescriptor* method = descriptor_->method(i);
289 : const Descriptor* type =
290 20 : (which == REQUEST) ? method->input_type() : method->output_type();
291 :
292 : map<string, string> sub_vars;
293 30 : sub_vars["index"] = SimpleItoa(i);
294 30 : sub_vars["type"] = ClassName(type, true);
295 :
296 : printer->Print(sub_vars,
297 : " case $index$:\n"
298 10 : " 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 8 : "\n");
308 8 : }
309 :
310 4 : void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
311 18 : for (int i = 0; i < descriptor_->method_count(); i++) {
312 39 : const MethodDescriptor* method = descriptor_->method(i);
313 : map<string, string> sub_vars;
314 10 : sub_vars["classname"] = descriptor_->name();
315 10 : sub_vars["name"] = method->name();
316 15 : sub_vars["index"] = SimpleItoa(i);
317 15 : sub_vars["input_type"] = ClassName(method->input_type(), true);
318 15 : 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 5 : "}\n");
328 : }
329 4 : }
330 :
331 : } // namespace cpp
332 : } // namespace compiler
333 : } // namespace protobuf
334 : } // namespace google
|