1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "generator/internal/client_generator.h"
16 #include "google/cloud/internal/absl_str_cat_quiet.h"
17 #include "absl/memory/memory.h"
18 #include "generator/internal/codegen_utils.h"
19 #include "generator/internal/descriptor_utils.h"
20 #include "generator/internal/predicate_utils.h"
21 #include "generator/internal/printer.h"
22 #include <google/api/client.pb.h>
23 #include <google/protobuf/descriptor.h>
24
25 namespace google {
26 namespace cloud {
27 namespace generator_internal {
28
ClientGenerator(google::protobuf::ServiceDescriptor const * service_descriptor,VarsDictionary service_vars,std::map<std::string,VarsDictionary> service_method_vars,google::protobuf::compiler::GeneratorContext * context)29 ClientGenerator::ClientGenerator(
30 google::protobuf::ServiceDescriptor const* service_descriptor,
31 VarsDictionary service_vars,
32 std::map<std::string, VarsDictionary> service_method_vars,
33 google::protobuf::compiler::GeneratorContext* context)
34 : ServiceCodeGenerator("client_header_path", "client_cc_path",
35 service_descriptor, std::move(service_vars),
36 std::move(service_method_vars), context) {}
37
GenerateHeader()38 Status ClientGenerator::GenerateHeader() {
39 HeaderPrint(CopyrightLicenseFileHeader());
40 HeaderPrint( // clang-format off
41 "// Generated by the Codegen C++ plugin.\n"
42 "// If you make any local changes, they will be lost.\n"
43 "// source: $proto_file_name$\n"
44 "#ifndef $header_include_guard$\n"
45 "#define $header_include_guard$\n"
46 "\n");
47 // clang-format on
48
49 // includes
50 HeaderLocalIncludes({vars("connection_header_path"), "google/cloud/future.h",
51 "google/cloud/polling_policy.h",
52 "google/cloud/status_or.h", "google/cloud/version.h"});
53 HeaderSystemIncludes({"google/longrunning/operations.grpc.pb.h", "memory"});
54 HeaderPrint("\n");
55
56 auto result = HeaderOpenNamespaces();
57 if (!result.ok()) return result;
58
59 // Client Class
60 HeaderPrint( // clang-format off
61 "$class_comment_block$\n"
62 "class $client_class_name$ {\n"
63 " public:\n"
64 " explicit $client_class_name$(ConnectionOptions const& options = ConnectionOptions());\n"
65 " explicit $client_class_name$(std::shared_ptr<$connection_class_name$> connection);\n"
66 " ~$client_class_name$();\n"
67 "\n"
68 " //@{\n"
69 " // @name Copy and move support\n"
70 " $client_class_name$($client_class_name$ const&) = default;\n"
71 " $client_class_name$& operator=($client_class_name$ const&) = default;\n"
72 " $client_class_name$($client_class_name$&&) noexcept = default;\n"
73 " $client_class_name$& operator=($client_class_name$&&) noexcept = default;\n"
74 " //@}\n"
75 "\n"
76 " //@{\n"
77 " // @name Equality\n"
78 " friend bool operator==($client_class_name$ const& a, $client_class_name$ const& b) {\n"
79 " return a.connection_ == b.connection_;\n"
80 " }\n"
81 " friend bool operator!=($client_class_name$ const& a, $client_class_name$ const& b) {\n"
82 " return !(a == b);\n"
83 " }\n"
84 " //@}\n"
85 "\n");
86 // clang-format on
87
88 for (google::protobuf::MethodDescriptor const& method : methods()) {
89 auto method_signature_extension =
90 method.options().GetRepeatedExtension(google::api::method_signature);
91 for (int i = 0; i < method_signature_extension.size(); ++i) {
92 std::string method_string =
93 absl::StrCat(" $method_name$($method_signature", i, "$);\n\n");
94 HeaderPrintMethod(
95 method,
96 {MethodPattern(
97 {
98 {" $method_signature_comment_block$\n"},
99 {IsResponseTypeEmpty,
100 // clang-format off
101 " Status\n",
102 " StatusOr<$response_type$>\n"},
103 {method_string}
104 // clang-format on
105 },
106 All(IsNonStreaming, Not(IsLongrunningOperation),
107 Not(IsPaginated))),
108 MethodPattern(
109 {
110 {" $method_signature_comment_block$\n"},
111 {IsResponseTypeEmpty,
112 // clang-format off
113 " future<Status>\n",
114 " future<StatusOr<$longrunning_deduced_response_type$>>\n"},
115 {method_string}
116 // clang-format on
117 },
118 All(IsNonStreaming, IsLongrunningOperation, Not(IsPaginated))),
119 MethodPattern(
120 {
121 // clang-format off
122 {" $method_signature_comment_block$\n"
123 " $method_name$Range\n"},
124 {method_string},
125 // clang-format on
126 },
127 All(IsNonStreaming, Not(IsLongrunningOperation), IsPaginated))},
128 __FILE__, __LINE__);
129 }
130 }
131
132 for (auto const& method : methods()) {
133 HeaderPrintMethod(
134 method,
135 {MethodPattern(
136 {
137 {" $request_comment_block$\n"},
138 {IsResponseTypeEmpty,
139 // clang-format off
140 " Status\n",
141 " StatusOr<$response_type$>\n"},
142 {" $method_name$($request_type$ const& request);\n"
143 "\n"}
144 // clang-format on
145 },
146 All(IsNonStreaming, Not(IsLongrunningOperation),
147 Not(IsPaginated))),
148 MethodPattern(
149 {
150 {" $request_comment_block$\n"},
151 {IsResponseTypeEmpty,
152 // clang-format off
153 " future<Status>\n",
154 " future<StatusOr<$longrunning_deduced_response_type$>>\n"},
155 {" $method_name$($request_type$ const& request);\n"
156 "\n"}
157 // clang-format on
158 },
159 All(IsNonStreaming, IsLongrunningOperation, Not(IsPaginated))),
160 MethodPattern(
161 {
162 // clang-format off
163 {" $request_comment_block$\n"},
164 {" $method_name$Range\n"
165 " $method_name$($request_type$ request);\n\n"},
166 // clang-format on
167 },
168 All(IsNonStreaming, Not(IsLongrunningOperation), IsPaginated))},
169 __FILE__, __LINE__);
170 }
171
172 HeaderPrint( // clang-format off
173 " private:\n"
174 " std::shared_ptr<$connection_class_name$> connection_;\n");
175 // clang-format on
176
177 // close Client class
178 HeaderPrint( // clang-format off
179 "};\n\n");
180 // clang-format on
181
182 HeaderCloseNamespaces();
183 // close header guard
184 HeaderPrint( // clang-format off
185 "#endif // $header_include_guard$\n");
186 // clang-format on
187 return {};
188 }
189
GenerateCc()190 Status ClientGenerator::GenerateCc() {
191 CcPrint(CopyrightLicenseFileHeader());
192 CcPrint( // clang-format off
193 "// Generated by the Codegen C++ plugin.\n"
194 "// If you make any local changes, they will be lost.\n"
195 "// source: $proto_file_name$\n\n");
196 // clang-format on
197
198 // includes
199 CcLocalIncludes({vars("client_header_path")});
200 CcSystemIncludes({"memory"});
201 CcPrint("\n");
202
203 auto result = CcOpenNamespaces();
204 if (!result.ok()) return result;
205
206 CcPrint( // clang-format off
207 "$client_class_name$::$client_class_name$(ConnectionOptions const& options)\n"
208 " : connection_(Make$connection_class_name$(options)) {}\n");
209 // clang-format on
210
211 CcPrint( // clang-format off
212 "$client_class_name$::$client_class_name$(std::shared_ptr<$connection_class_name$> connection)"
213 " : connection_(std::move(connection)) {}\n");
214 // clang-format on
215
216 CcPrint( // clang-format off
217 "$client_class_name$::~$client_class_name$() = default;\n\n");
218 // clang-format on
219
220 for (google::protobuf::MethodDescriptor const& method : methods()) {
221 auto method_signature_extension =
222 method.options().GetRepeatedExtension(google::api::method_signature);
223 for (int i = 0; i < method_signature_extension.size(); ++i) {
224 std::string method_string = absl::StrCat(
225 "$client_class_name$::$method_name$($method_signature", i, "$) {\n");
226 std::string method_request_string =
227 absl::StrCat("$method_request_setters", i, "$");
228 CcPrintMethod(
229 method,
230 {MethodPattern(
231 {
232 {IsResponseTypeEmpty,
233 // clang-format off
234 "Status\n",
235 "StatusOr<$response_type$>\n"},
236 {method_string},
237 {" $request_type$ request;\n"},
238 {method_request_string},
239 {" return connection_->$method_name$(request);\n"
240 "}\n\n"}
241 // clang-format on
242 },
243 All(IsNonStreaming, Not(IsLongrunningOperation),
244 Not(IsPaginated))),
245 MethodPattern(
246 {
247 {IsResponseTypeEmpty,
248 // clang-format off
249 "future<Status>\n",
250 "future<StatusOr<$longrunning_deduced_response_type$>>\n"},
251 {method_string},
252 {" $request_type$ request;\n"},
253 {method_request_string},
254 {" return connection_->$method_name$(request);\n"
255 "}\n\n"}
256 // clang-format on
257 },
258 All(IsNonStreaming, IsLongrunningOperation, Not(IsPaginated))),
259 MethodPattern(
260 {
261 // clang-format off
262 {"$method_name$Range\n"},
263 {method_string},
264 {" $request_type$ request;\n"},
265 {method_request_string},
266 {" return connection_->$method_name$(request);\n"
267 "}\n\n"}
268 // clang-format on
269 },
270 All(IsNonStreaming, Not(IsLongrunningOperation), IsPaginated))},
271 __FILE__, __LINE__);
272 }
273 }
274
275 for (auto const& method : methods()) {
276 CcPrintMethod(
277 method,
278 {MethodPattern(
279 {
280 {IsResponseTypeEmpty,
281 // clang-format off
282 "Status\n",
283 "StatusOr<$response_type$>\n"},
284 {"$client_class_name$::$method_name$($request_type$ const& request) {\n"
285 " return connection_->$method_name$(request);\n"
286 "}\n\n"}
287 // clang-format on
288 },
289 All(IsNonStreaming, Not(IsLongrunningOperation),
290 Not(IsPaginated))),
291 MethodPattern(
292 {
293 {IsResponseTypeEmpty,
294 // clang-format off
295 "future<Status>\n",
296 "future<StatusOr<$longrunning_deduced_response_type$>>\n"},
297 {"$client_class_name$::$method_name$($request_type$ const& request) {\n"
298 " return connection_->$method_name$(request);\n"
299 "}\n\n"}
300 // clang-format on
301 },
302 All(IsNonStreaming, IsLongrunningOperation, Not(IsPaginated))),
303 MethodPattern(
304 {
305 // clang-format off
306 {"$method_name$Range\n"
307 "$client_class_name$::$method_name$($request_type$ request) {\n"
308 " return connection_->$method_name$(request);\n"
309 "}\n\n"}
310 // clang-format on
311 },
312 All(IsNonStreaming, Not(IsLongrunningOperation), IsPaginated))},
313 __FILE__, __LINE__);
314 }
315
316 CcCloseNamespaces();
317 return {};
318 }
319
320 } // namespace generator_internal
321 } // namespace cloud
322 } // namespace google
323