• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 *reinterpret_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