Skip to content

Commit

Permalink
[ggj][codegen] feat: add codes def to ServiceStubSettings (#238)
Browse files Browse the repository at this point in the history
* feat: add factory var decl in ServiceStubSettings codegen

* fix: prevent duplicate MethodDefinition annotations

* feat: add descriptor fields to ServiceStubSettings codegen

* feat: add starter Builder to ServiceStubSettings codegen

* feat: add settings.builder decls to ServiceStubSettings codegen

* feat: add first nested ctors to ServiceStubSettings codegen

* feat: add GapicServiceConfig DS and processing

* feat: integrate GapicServiceConfig into GapicContext, Parser, Composer

* feat: initial param block, RetrySettingsComposer, test

* fix!: refactor GapicRetrySettings

* fix: recognize 1. or .1 double patterns

* feat: support BlockStatement in ClassDef stmts

* feat: add params block to ServiceStubSettings codegen

* feat: add codes def to ServiceStubSettings codegen
  • Loading branch information
miraleung authored Aug 29, 2020
1 parent f59e1e9 commit 9204030
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ java_library(
deps = [
"//:longrunning_java_proto",
"//:monitored_resource_java_proto",
"//:rpc_java_proto",
"//:service_config_java_proto",
"//src/main/java/com/google/api/generator/engine/ast",
"//src/main/java/com/google/api/generator/gapic:status_java_proto",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
package com.google.api.generator.gapic.composer;

import com.google.api.gax.retrying.RetrySettings;
import com.google.api.gax.rpc.StatusCode;
import com.google.api.generator.engine.ast.AssignmentExpr;
import com.google.api.generator.engine.ast.BlockStatement;
import com.google.api.generator.engine.ast.ConcreteReference;
import com.google.api.generator.engine.ast.EnumRefExpr;
import com.google.api.generator.engine.ast.Expr;
import com.google.api.generator.engine.ast.ExprStatement;
import com.google.api.generator.engine.ast.MethodInvocationExpr;
Expand All @@ -33,8 +35,11 @@
import com.google.api.generator.gapic.model.Service;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.protobuf.Duration;
import com.google.protobuf.util.Durations;
import com.google.rpc.Code;
import io.grpc.serviceconfig.MethodConfig.RetryPolicy;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -45,6 +50,8 @@

public class RetrySettingsComposer {
private static final Map<String, TypeNode> STATIC_TYPES = createStaticTypes();
private static final TypeNode STATUS_CODE_CODE_TYPE =
TypeNode.withReference(ConcreteReference.withClazz(StatusCode.Code.class));

public static BlockStatement createRetryParamDefinitionsBlock(
Service service,
Expand Down Expand Up @@ -116,6 +123,88 @@ public static BlockStatement createRetryParamDefinitionsBlock(
.build();
}

public static BlockStatement createRetryCodesDefinitionsBlock(
Service service,
GapicServiceConfig serviceConfig,
VariableExpr retryCodesDefinitionsClassMemberVarExpr) {
TypeNode definitionsType =
TypeNode.withReference(
ConcreteReference.builder()
.setClazz(ImmutableMap.Builder.class)
.setGenerics(retryCodesDefinitionsClassMemberVarExpr.type().reference().generics())
.build());
VariableExpr definitionsVarExpr =
VariableExpr.withVariable(
Variable.builder().setType(definitionsType).setName("definitions").build());

List<Expr> bodyExprs = new ArrayList<>();
// Create the first expr.
bodyExprs.add(
AssignmentExpr.builder()
.setVariableExpr(definitionsVarExpr.toBuilder().setIsDecl(true).build())
.setValueExpr(
MethodInvocationExpr.builder()
.setStaticReferenceType(STATIC_TYPES.get("ImmutableMap"))
.setMethodName("builder")
.setReturnType(definitionsVarExpr.type())
.build())
.build());

for (Map.Entry<String, List<Code>> codeEntry :
serviceConfig.getAllRetryCodes(service).entrySet()) {
bodyExprs.add(
createRetryCodeDefinitionExpr(
codeEntry.getKey(), codeEntry.getValue(), definitionsVarExpr));
}

// Reassign the new codes.
bodyExprs.add(
AssignmentExpr.builder()
.setVariableExpr(retryCodesDefinitionsClassMemberVarExpr)
.setValueExpr(
MethodInvocationExpr.builder()
.setExprReferenceExpr(definitionsVarExpr)
.setMethodName("build")
.setReturnType(retryCodesDefinitionsClassMemberVarExpr.type())
.build())
.build());

// Put everything together.
return BlockStatement.builder()
.setIsStatic(true)
.setBody(
bodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()))
.build();
}

private static Expr createRetryCodeDefinitionExpr(
String codeName, List<Code> retryCodes, VariableExpr definitionsVarExpr) {
// Construct something like `definitions.put("code_name",
// ImmutableSet.copYOf(Lists.<StatusCode.Code>newArrayList()));`
MethodInvocationExpr codeListExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(STATIC_TYPES.get("Lists"))
.setGenerics(Arrays.asList(STATUS_CODE_CODE_TYPE.reference()))
.setMethodName("newArrayList")
.setArguments(
retryCodes.stream()
.map(c -> toStatusCodeEnumRefExpr(c))
.collect(Collectors.toList()))
.build();

MethodInvocationExpr codeSetExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(STATIC_TYPES.get("ImmutableSet"))
.setMethodName("copyOf")
.setArguments(codeListExpr)
.build();
return MethodInvocationExpr.builder()
.setExprReferenceExpr(definitionsVarExpr)
.setMethodName("put")
.setArguments(ValueExpr.withValue(StringObjectValue.withValue(codeName)), codeSetExpr)
.build();
}

private static List<Expr> createRetrySettingsExprs(
String settingsName,
GapicRetrySettings settings,
Expand Down Expand Up @@ -240,9 +329,19 @@ private static List<Expr> createRetrySettingsExprs(
return Arrays.asList(settingsAssignExpr, definitionsPutExpr);
}

private static EnumRefExpr toStatusCodeEnumRefExpr(Code code) {
return EnumRefExpr.builder().setType(STATUS_CODE_CODE_TYPE).setName(code.name()).build();
}

private static Map<String, TypeNode> createStaticTypes() {
List<Class> concreteClazzes =
Arrays.asList(org.threeten.bp.Duration.class, ImmutableMap.class, RetrySettings.class);
Arrays.asList(
org.threeten.bp.Duration.class,
ImmutableMap.class,
ImmutableSet.class,
Lists.class,
RetrySettings.class,
StatusCode.class);
return concreteClazzes.stream()
.collect(
Collectors.toMap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ private static List<Statement> createNestedClassStatements(
.map(v -> varDeclFn.apply(v))
.collect(Collectors.toList()));

// Declare the RETRYABLE_CODE_DEFNITIONS field.
// Declare the RETRYABLE_CODE_DEFINITIONS field.
Function<VariableExpr, VariableExpr> varStaticDeclFn =
v ->
v.toBuilder()
Expand All @@ -1135,8 +1135,13 @@ private static List<Statement> createNestedClassStatements(
List<Statement> statements = new ArrayList<>();
statements.addAll(
exprs.stream().map(e -> exprStatementFn.apply(e)).collect(Collectors.toList()));

// Declare and set the RETRYABLE_CODE_DEFINITIONS field.
statements.add(
exprStatementFn.apply((varStaticDeclFn.apply(NESTED_RETRYABLE_CODE_DEFINITIONS_VAR_EXPR))));
statements.add(
RetrySettingsComposer.createRetryCodesDefinitionsBlock(
service, serviceConfig, NESTED_RETRYABLE_CODE_DEFINITIONS_VAR_EXPR));

// Declare the RETRY_PARAM_DEFINITIONS field.
statements.add(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ filegroup(
],
test_class = "com.google.api.generator.gapic.composer.{0}".format(test_name),
deps = [
"//:rpc_java_proto",
"//:service_config_java_proto",
"//src/main/java/com/google/api/generator/engine/ast",
"//src/main/java/com/google/api/generator/engine/writer",
"//src/main/java/com/google/api/generator/gapic/composer",
"//src/main/java/com/google/api/generator/gapic/model",
"//src/main/java/com/google/api/generator/gapic/protoparser",
"//src/test/java/com/google/api/generator/gapic/testdata:showcase_java_proto",
"@com_google_api_gax_java//jar",
"@com_google_protobuf//:protobuf_java",
"@com_google_truth_truth//jar",
"@junit_junit//jar",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;

import com.google.api.gax.rpc.StatusCode;
import com.google.api.generator.engine.ast.BlockStatement;
import com.google.api.generator.engine.ast.ConcreteReference;
import com.google.api.generator.engine.ast.TypeNode;
Expand All @@ -31,6 +32,7 @@
import com.google.api.generator.gapic.protoparser.Parser;
import com.google.api.generator.gapic.protoparser.ServiceConfigParser;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.ServiceDescriptor;
import com.google.showcase.v1beta1.EchoOuterClass;
Expand All @@ -51,6 +53,8 @@ public class RetrySettingsComposerTest {
"src/test/java/com/google/api/generator/gapic/testdata/";
private static final VariableExpr RETRY_PARAM_DEFINITIONS_VAR_EXPR =
createRetryParamDefinitionsVarExpr();
private static final VariableExpr RETRY_CODES_DEFINITIONS_VAR_EXPR =
createRetryableCodesDefinitionsVarExpr();

private JavaWriterVisitor writerVisitor;

Expand Down Expand Up @@ -135,6 +139,101 @@ public void paramDefinitionsBlock_basic() {
assertEquals(expected, writerVisitor.write());
}

@Test
public void codesDefinitionsBlock_noConfigsFound() {
FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor();
ServiceDescriptor echoServiceDescriptor = echoFileDescriptor.getServices().get(0);
Map<String, Message> messageTypes = Parser.parseMessages(echoFileDescriptor);
Map<String, ResourceName> resourceNames = Parser.parseResourceNames(echoFileDescriptor);
Set<ResourceName> outputResourceNames = new HashSet<>();
List<Service> services =
Parser.parseService(echoFileDescriptor, messageTypes, resourceNames, outputResourceNames);
assertEquals(1, services.size());

Service service = services.get(0);

String jsonFilename = "retrying_grpc_service_config.json";
Path jsonPath = Paths.get(JSON_DIRECTORY, jsonFilename);
Optional<GapicServiceConfig> serviceConfigOpt = ServiceConfigParser.parse(jsonPath.toString());
assertTrue(serviceConfigOpt.isPresent());
GapicServiceConfig serviceConfig = serviceConfigOpt.get();

BlockStatement paramDefinitionsBlock =
RetrySettingsComposer.createRetryCodesDefinitionsBlock(
service, serviceConfig, RETRY_CODES_DEFINITIONS_VAR_EXPR);

paramDefinitionsBlock.accept(writerVisitor);
String expected =
createLines(
"static {\n",
"ImmutableMap.Builder<String, ImmutableSet<StatusCode.Code>> definitions ="
+ " ImmutableMap.builder();\n",
"definitions.put(\"no_retry_codes\","
+ " ImmutableSet.copyOf(Lists.<StatusCode.Code>newArrayList()));\n",
"RETRYABLE_CODE_DEFINITIONS = definitions.build();\n",
"}\n");
assertEquals(expected, writerVisitor.write());
}

@Test
public void codesDefinitionsBlock_basic() {
FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor();
ServiceDescriptor echoServiceDescriptor = echoFileDescriptor.getServices().get(0);
Map<String, Message> messageTypes = Parser.parseMessages(echoFileDescriptor);
Map<String, ResourceName> resourceNames = Parser.parseResourceNames(echoFileDescriptor);
Set<ResourceName> outputResourceNames = new HashSet<>();
List<Service> services =
Parser.parseService(echoFileDescriptor, messageTypes, resourceNames, outputResourceNames);
assertEquals(1, services.size());

Service service = services.get(0);

String jsonFilename = "showcase_grpc_service_config.json";
Path jsonPath = Paths.get(JSON_DIRECTORY, jsonFilename);
Optional<GapicServiceConfig> serviceConfigOpt = ServiceConfigParser.parse(jsonPath.toString());
assertTrue(serviceConfigOpt.isPresent());
GapicServiceConfig serviceConfig = serviceConfigOpt.get();

BlockStatement paramDefinitionsBlock =
RetrySettingsComposer.createRetryCodesDefinitionsBlock(
service, serviceConfig, RETRY_CODES_DEFINITIONS_VAR_EXPR);

paramDefinitionsBlock.accept(writerVisitor);
String expected =
createLines(
"static {\n",
"ImmutableMap.Builder<String, ImmutableSet<StatusCode.Code>> definitions ="
+ " ImmutableMap.builder();\n",
"definitions.put(\"retry_policy_1_codes\","
+ " ImmutableSet.copyOf(Lists.<StatusCode.Code>newArrayList(StatusCode.Code.UNAVAILABLE,"
+ " StatusCode.Code.UNKNOWN)));\n",
"definitions.put(\"no_retry_0_codes\","
+ " ImmutableSet.copyOf(Lists.<StatusCode.Code>newArrayList()));\n",
"RETRYABLE_CODE_DEFINITIONS = definitions.build();\n",
"}\n");
assertEquals(expected, writerVisitor.write());
}

private static VariableExpr createRetryableCodesDefinitionsVarExpr() {
TypeNode immutableSetType =
TypeNode.withReference(
ConcreteReference.builder()
.setClazz(ImmutableSet.class)
.setGenerics(Arrays.asList(ConcreteReference.withClazz(StatusCode.Code.class)))
.build());
TypeNode varType =
TypeNode.withReference(
ConcreteReference.builder()
.setClazz(ImmutableMap.class)
.setGenerics(
Arrays.asList(TypeNode.STRING, immutableSetType).stream()
.map(t -> t.reference())
.collect(Collectors.toList()))
.build());
return VariableExpr.withVariable(
Variable.builder().setType(varType).setName("RETRYABLE_CODE_DEFINITIONS").build());
}

private static VariableExpr createRetryParamDefinitionsVarExpr() {
TypeNode retrySettingsType =
TypeNode.withReference(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public void generateServiceClasses() {
+ "import com.google.common.collect.ImmutableList;\n"
+ "import com.google.common.collect.ImmutableMap;\n"
+ "import com.google.common.collect.ImmutableSet;\n"
+ "import com.google.common.collect.Lists;\n"
+ "import com.google.longrunning.Operation;\n"
+ "import com.google.showcase.v1beta1.BlockRequest;\n"
+ "import com.google.showcase.v1beta1.BlockResponse;\n"
Expand Down Expand Up @@ -352,6 +353,21 @@ public void generateServiceClasses() {
+ " blockSettings;\n"
+ " private static final ImmutableMap<String, ImmutableSet<StatusCode.Code>>\n"
+ " RETRYABLE_CODE_DEFINITIONS;\n"
+ "\n"
+ " static {\n"
+ " ImmutableMap.Builder<String, ImmutableSet<StatusCode.Code>> definitions =\n"
+ " ImmutableMap.builder();\n"
+ " definitions.put(\n"
+ " \"retry_policy_1_codes\",\n"
+ " ImmutableSet.copyOf(\n"
+ " Lists.<StatusCode.Code>newArrayList(\n"
+ " StatusCode.Code.UNAVAILABLE, StatusCode.Code.UNKNOWN)));\n"
+ " definitions.put(\n"
+ " \"no_retry_0_codes\","
+ " ImmutableSet.copyOf(Lists.<StatusCode.Code>newArrayList()));\n"
+ " RETRYABLE_CODE_DEFINITIONS = definitions.build();\n"
+ " }\n"
+ "\n"
+ " private static final ImmutableMap<String, RetrySettings>"
+ " RETRY_PARAM_DEFINITIONS;\n"
+ "\n"
Expand Down

0 comments on commit 9204030

Please sign in to comment.