Skip to content

Commit 9c1df0f

Browse files
authored
Add client Stub abstract class generation and make rpc wrapper methods (googleapis#16)
This is a brutally simple first pass at creating the client service class and associated Stub abstract class. Only synchronous, unary rpcs are supported. Caveats: * There is no retry in the client methods. * Include directives that reference generated headers for the grpc service and associated messages lack complete paths. * There is no concrete child of the abstract generated Stub class. ** There are therefore no factories for a Stub class. * Formatting in the generated code is best effort. * There is no easy way to build the generated client. ** There are no tests that _use_ the generated code.
1 parent 069f3ea commit 9c1df0f

17 files changed

+752
-77
lines changed

generator/BUILD.bazel

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,16 @@ cc_library(
2020
name = "cpp_gapic_generator",
2121
srcs = [
2222
"gapic_generator.cc",
23-
"internal/client_header_generator.cc",
24-
"internal/client_header_generator.h",
2523
"internal/client_cc_generator.cc",
2624
"internal/client_cc_generator.h",
25+
"internal/stub_cc_generator.cc",
26+
"internal/stub_cc_generator.h",
27+
"internal/client_header_generator.cc",
28+
"internal/client_header_generator.h",
29+
"internal/stub_header_generator.cc",
30+
"internal/stub_header_generator.h",
2731
"internal/data_model.h",
32+
"internal/gapic_utils.cc",
2833
"internal/gapic_utils.h",
2934
"internal/printer.h",
3035
],
@@ -34,8 +39,8 @@ cc_library(
3439
deps = [
3540
"@absl//absl/base",
3641
"@absl//absl/strings",
37-
"@com_google_protobuf//:protoc_lib",
3842
"@api_common_protos//google/api:client_cc_proto",
43+
"@com_google_protobuf//:protoc_lib",
3944
],
4045
)
4146

@@ -49,29 +54,31 @@ cc_binary(
4954

5055
cc_test(
5156
name = "gapic_generator_unittest",
57+
size = "small",
5258
srcs = ["gapic_generator_unittest.cc"],
53-
deps = [
54-
"//generator:cpp_gapic_generator",
55-
"@gtest//:gtest_main",
56-
],
5759
data = glob(
5860
["testdata/**"],
5961
) + [
6062
"@api_common_protos//google/api:client_proto",
6163
],
64+
deps = [
65+
"//generator:cpp_gapic_generator",
66+
"@gtest//:gtest_main",
67+
],
6268
)
6369

6470
generator_unit_tests = [
65-
"internal/gapic_utils_unittest.cc"
71+
"internal/gapic_utils_unittest.cc",
6672
]
6773

6874
[cc_test(
6975
name = "generator_" + test.replace("/", "_").replace(".cc", ""),
76+
size = "small",
7077
srcs = [test],
7178
deps = [
79+
"//generator:cpp_gapic_generator",
7280
"@absl//absl/base",
7381
"@absl//absl/strings",
74-
"//generator:cpp_gapic_generator",
7582
"@gtest//:gtest_main",
7683
],
7784
) for test in generator_unit_tests]

generator/gapic_generator.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include "generator/internal/data_model.h"
2626
#include "generator/internal/gapic_utils.h"
2727
#include "generator/internal/printer.h"
28+
#include "generator/internal/stub_cc_generator.h"
29+
#include "generator/internal/stub_header_generator.h"
2830

2931
#include "google/api/client.pb.h"
3032

@@ -63,11 +65,28 @@ bool GapicGenerator::Generate(pb::FileDescriptor const* file,
6365
return false;
6466
}
6567

68+
std::string header_stub_file_path =
69+
absl::StrCat(service_file_path, "_stub", ".gapic.h");
70+
internal::Printer header_stub_printer(generator_context,
71+
header_stub_file_path);
72+
if (!internal::GenerateClientStubHeader(service, vars, header_stub_printer,
73+
error)) {
74+
return false;
75+
}
76+
6677
std::string cc_file_path = absl::StrCat(service_file_path, ".gapic.cc");
6778
internal::Printer cc_printer(generator_context, cc_file_path);
6879
if (!internal::GenerateClientCC(service, vars, cc_printer, error)) {
6980
return false;
7081
}
82+
83+
std::string cc_stub_file_path =
84+
absl::StrCat(service_file_path, "_stub", ".gapic.cc");
85+
internal::Printer cc_stub_printer(generator_context, cc_stub_file_path);
86+
if (!internal::GenerateClientStubCC(service, vars, cc_stub_printer,
87+
error)) {
88+
return false;
89+
}
7190
}
7291
return true;
7392
}

generator/gapic_generator_unittest.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,10 @@ TEST(CppGapicPluginTest, GapicPluginTest) {
8080

8181
std::vector<std::string> files_to_check{
8282
"google/example/library/v1/library_service.gapic.h",
83-
"google/example/library/v1/library_service.gapic.cc"};
83+
"google/example/library/v1/library_service.gapic.cc",
84+
"google/example/library/v1/library_service_stub.gapic.h",
85+
"google/example/library/v1/library_service_stub.gapic.cc",
86+
};
8487

8588
for (std::string const& f : files_to_check) {
8689
std::string actual_file = absl::StrCat(gapic_out_dir, "/", f);

generator/internal/client_cc_generator.cc

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <sstream>
1717
#include <string>
1818

19+
#include "gapic_utils.h"
1920
#include "printer.h"
2021
#include "src/google/protobuf/descriptor.h"
2122
#include "generator/internal/client_cc_generator.h"
@@ -29,8 +30,15 @@ namespace codegen {
2930
namespace internal {
3031

3132
std::vector<std::string> BuildClientCCIncludes(
32-
pb::ServiceDescriptor const* /* service */) {
33-
return std::vector<std::string>();
33+
pb::ServiceDescriptor const* service) {
34+
return {
35+
LocalInclude(absl::StrCat(
36+
internal::ServiceNameToFilePath(service->name()), ".gapic.h")),
37+
LocalInclude(absl::StrCat(
38+
internal::ServiceNameToFilePath(service->name()), "_stub.gapic.h")),
39+
LocalInclude("gax/status.h"),
40+
LocalInclude("gax/status_or.h"),
41+
};
3442
}
3543

3644
std::vector<std::string> BuildClientCCNamespaces(
@@ -47,27 +55,43 @@ bool GenerateClientCC(pb::ServiceDescriptor const* service,
4755
p->Print(vars,
4856
"// Generated by the GAPIC C++ plugin.\n"
4957
"// If you make any local changes, they will be lost.\n"
50-
"// source: $proto_file_name$");
58+
"// source: $proto_file_name$\n");
5159

5260
for (auto include : includes) {
53-
p->Print("\n#include $include$", "include", include);
61+
p->Print("#include $include$\n", "include", include);
5462
}
5563
for (auto nspace : namespaces) {
56-
p->Print("\nnamespace $namespace$ {", "namespace", nspace);
64+
p->Print("namespace $namespace$ {\n", "namespace", nspace);
5765
}
5866

59-
p->Print(vars,
60-
"\n"
61-
"// TODO: add content");
67+
p->Print("\n");
68+
69+
DataModel::PrintMethods(
70+
service, vars, p,
71+
"gax::StatusOr<$response_object$>\n"
72+
"$class_name$::$method_name$(\n"
73+
"$request_object$ const& request) {\n"
74+
" // TODO: actual useful work, e.g. retry, backoff, metadata, "
75+
"pagination, etc.\n"
76+
" grpc::ClientContext context;\n"
77+
" $response_object$ response;\n"
78+
" grpc::Status status = stub_->$method_name$(&context, request, "
79+
"&response);\n"
80+
" if (status.ok()) {\n"
81+
" return response;\n"
82+
" } else {\n"
83+
" return gax::GrpcStatusToGaxStatus(status);\n"
84+
" }\n"
85+
"}\n"
86+
"\n",
87+
NoStreamingPredicate);
6288

6389
for (auto nspace : namespaces) {
6490
p->Print("\n} // namespace $namespace$", "namespace", nspace);
6591
}
6692

67-
p->Print("\n");
68-
6993
return true;
70-
}
94+
} // namespace internal
7195

7296
} // namespace internal
7397
} // namespace codegen

generator/internal/client_cc_generator.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,6 @@ namespace api {
2828
namespace codegen {
2929
namespace internal {
3030

31-
std::vector<std::string> BuildClientCCIncludes(
32-
pb::ServiceDescriptor const* /* service */);
33-
34-
std::vector<std::string> BuildClientCCNamespaces(
35-
pb::ServiceDescriptor const* /* service */);
36-
3731
bool GenerateClientCC(pb::ServiceDescriptor const* service,
3832
std::map<std::string, std::string> const& vars,
3933
Printer& p, std::string* /* error */);

generator/internal/client_header_generator.cc

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <sstream>
1717
#include <string>
1818

19+
#include "gapic_utils.h"
1920
#include "printer.h"
2021
#include "src/google/protobuf/descriptor.h"
2122
#include "generator/internal/client_header_generator.h"
@@ -29,8 +30,16 @@ namespace codegen {
2930
namespace internal {
3031

3132
std::vector<std::string> BuildClientHeaderIncludes(
32-
pb::ServiceDescriptor const* /* service */) {
33-
return std::vector<std::string>();
33+
pb::ServiceDescriptor const* service) {
34+
return {
35+
SystemInclude("memory"),
36+
LocalInclude(absl::StrCat(
37+
internal::ServiceNameToFilePath(service->name()), "_stub.gapic.h")),
38+
LocalInclude(absl::StrCat(service->name(), ".pb.h")),
39+
LocalInclude("gax/status_or.h"),
40+
LocalInclude("gax/retry_policy.h"),
41+
LocalInclude("gax/backoff_policy.h"),
42+
};
3443
}
3544

3645
std::vector<std::string> BuildClientHeaderNamespaces(
@@ -49,31 +58,73 @@ bool GenerateClientHeader(pb::ServiceDescriptor const* service,
4958
"// If you make any local changes, they will be lost.\n"
5059
"// source: $proto_file_name$\n"
5160
"#ifndef $header_include_guard_const$\n"
52-
"#define $header_include_guard_const$");
61+
"#define $header_include_guard_const$\n"
62+
"\n");
5363

5464
for (auto include : includes) {
55-
p->Print("\n#include $include$", "include", include);
65+
p->Print("#include $include$\n", "include", include);
5666
}
67+
5768
for (auto nspace : namespaces) {
58-
p->Print("\nnamespace $namespace$ {", "namespace", nspace);
69+
p->Print("namespace $namespace$ {\n", "namespace", nspace);
5970
}
6071

6172
p->Print(vars,
6273
"\n"
6374
"$class_comment_block$\n"
64-
"class $class_name$ {");
65-
66-
DataModel::PrintMethods(service, vars, p, "");
67-
68-
p->Print(vars, "\n}; // $class_name$");
75+
"class $class_name$ final {\n"
76+
" public:\n"
77+
" $class_name$(std::shared_ptr<$stub_class_name$> stub) : \n"
78+
" stub_(std::move(stub)) {}\n"
79+
"\n"
80+
" template<typename... Policies>\n"
81+
" $class_name$(std::shared_ptr<$stub_class_name$> stub, \n"
82+
" Policies&&... policies) : $class_name$(std::move(stub)) {\n"
83+
" ChangePolicies(std::forward<policies>...);\n"
84+
" }\n"
85+
"\n"
86+
" $class_name$($class_name$ const&) = delete;\n"
87+
" $class_name$& operator=($class_name$ const&) = delete;\n"
88+
"\n"
89+
" std::shared_ptr<$stub_class_name$> Stub() { return stub_; }\n"
90+
"\n");
91+
92+
DataModel::PrintMethods(
93+
service, vars, p,
94+
" gax::StatusOr<$response_object$> \n"
95+
" $method_name$($request_object$ const& request);\n"
96+
"\n",
97+
NoStreamingPredicate);
98+
99+
p->Print(
100+
vars,
101+
"\n"
102+
" private:\n"
103+
" void ChangePolicy(gax::RetryPolicy const& policy) {\n"
104+
" retry_policy_ = policy.clone();\n"
105+
" }\n"
106+
" void ChangePolicy(gax::BackoffPolicy const& policy) {\n"
107+
" backoff_policy_ = policy.clone();\n"
108+
" }\n"
109+
" void ChangePolicies() {}\n"
110+
"\n"
111+
" template <typename Policy, typename... Policies>\n"
112+
" void ChangePolicies(Policy&& policy, Policies&&... policies) {\n"
113+
" ChangePolicy(policy);\n"
114+
" ChangePolicies(std::forward<Policies>(policies)...);\n"
115+
" }\n"
116+
"\n"
117+
" std::shared_ptr<$stub_class_name$> stub_;\n"
118+
" std::unique_ptr<gax::RetryPolicy> retry_policy_;\n"
119+
" std::unique_ptr<gax::BackoffPolicy> backoff_policy_;\n"
120+
"}; // $class_name$\n"
121+
"\n");
69122

70123
for (auto nspace : namespaces) {
71-
p->Print("\n} // namespace $namespace$", "namespace", nspace);
124+
p->Print("} // namespace $namespace$\n", "namespace", nspace);
72125
}
73126

74-
p->Print(vars,
75-
"\n"
76-
"#endif // $header_include_guard_const$\n");
127+
p->Print(vars, "#endif // $header_include_guard_const$\n");
77128

78129
return true;
79130
}

generator/internal/data_model.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <algorithm>
1818
#include <cctype>
19+
#include <functional>
1920
#include <string>
2021

2122
#include "absl/strings/str_cat.h"
@@ -41,8 +42,11 @@ struct DataModel {
4142
static void SetServiceVars(pb::ServiceDescriptor const* service,
4243
std::map<std::string, std::string>& vars) {
4344
vars["class_name"] = service->name();
45+
vars["stub_class_name"] = absl::StrCat(service->name(), "Stub");
4446
vars["proto_file_name"] = service->file()->name();
4547
vars["header_include_guard_const"] = absl::StrCat(service->name(), "_H_");
48+
vars["stub_header_include_guard_const"] =
49+
absl::StrCat(service->name(), "_Stub", "_H_");
4650
vars["class_comment_block"] = "// TODO: pull in comments";
4751
vars["grpc_stub_fqn"] = internal::ProtoNameToCppName(service->full_name());
4852
vars["service_endpoint"] =
@@ -58,13 +62,17 @@ struct DataModel {
5862
internal::ProtoNameToCppName(method->output_type()->full_name());
5963
}
6064

61-
static void PrintMethods(pb::ServiceDescriptor const* service,
62-
std::map<std::string, std::string> vars, Printer& p,
63-
char const* tmplt) {
65+
static void PrintMethods(
66+
pb::ServiceDescriptor const* service,
67+
std::map<std::string, std::string> vars, Printer& p, char const* tmplt,
68+
std::function<bool(pb::MethodDescriptor const*)> predicate =
69+
[](pb::MethodDescriptor const*) { return true; }) {
6470
for (int i = 0; i < service->method_count(); i++) {
6571
const pb::MethodDescriptor* method = service->method(i);
66-
SetMethodVars(method, vars);
67-
p->Print(vars, tmplt);
72+
if (predicate(method)) {
73+
SetMethodVars(method, vars);
74+
p->Print(vars, tmplt);
75+
}
6876
}
6977
}
7078
};

0 commit comments

Comments
 (0)