Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ java_library(
"@com_google_api_gax_java//jar",
"@com_google_code_findbugs_jsr305//jar",
"@com_google_guava_guava//jar",
"@com_google_protobuf//:protobuf_java",
"@com_google_protobuf//:protobuf_java_util",
"@com_google_protobuf//java/core",
"@io_grpc_java//api",
"@io_grpc_java//protobuf",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,25 @@
import com.google.api.generator.engine.ast.ExprStatement;
import com.google.api.generator.engine.ast.MethodInvocationExpr;
import com.google.api.generator.engine.ast.NullObjectValue;
import com.google.api.generator.engine.ast.PrimitiveValue;
import com.google.api.generator.engine.ast.StringObjectValue;
import com.google.api.generator.engine.ast.TypeNode;
import com.google.api.generator.engine.ast.ValueExpr;
import com.google.api.generator.engine.ast.Variable;
import com.google.api.generator.engine.ast.VariableExpr;
import com.google.api.generator.gapic.model.GapicRetrySettings;
import com.google.api.generator.gapic.model.GapicServiceConfig;
import com.google.api.generator.gapic.model.Service;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.protobuf.Duration;
import com.google.protobuf.util.Durations;
import io.grpc.serviceconfig.MethodConfig.RetryPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class RetrySettingsComposer {
Expand Down Expand Up @@ -78,7 +86,15 @@ public static BlockStatement createRetryParamDefinitionsBlock(
.build());

// Build the settings object for each config.
// TODO(miraleung): Fill this out.
for (Map.Entry<String, GapicRetrySettings> settingsEntry :
serviceConfig.getAllGapicRetrySettings(service).entrySet()) {
bodyExprs.addAll(
createRetrySettingsExprs(
settingsEntry.getKey(),
settingsEntry.getValue(),
settingsVarExpr,
definitionsVarExpr));
}

// Reassign the new settings.
bodyExprs.add(
Expand All @@ -100,6 +116,130 @@ public static BlockStatement createRetryParamDefinitionsBlock(
.build();
}

private static List<Expr> createRetrySettingsExprs(
String settingsName,
GapicRetrySettings settings,
VariableExpr settingsVarExpr,
VariableExpr definitionsVarExpr) {
Function<Duration, ValueExpr> durationToMillisValExprFn =
d ->
ValueExpr.withValue(
PrimitiveValue.builder()
.setType(TypeNode.LONG)
.setValue(String.format("%dL", Durations.toMillis(d)))
.build());
Function<Float, ValueExpr> floatToValExprFn =
f ->
ValueExpr.withValue(
PrimitiveValue.builder()
.setType(TypeNode.DOUBLE)
.setValue(String.format("%.1f", f))
.build());
Function<ValueExpr, MethodInvocationExpr> durationMillisMethodFn =
v ->
MethodInvocationExpr.builder()
.setStaticReferenceType(STATIC_TYPES.get("Duration"))
.setMethodName("ofMillis")
.setArguments(v)
.build();

Expr settingsBuilderExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(STATIC_TYPES.get("RetrySettings"))
.setMethodName("newBuilder")
.build();

RetryPolicy retryPolicy = settings.retryPolicy();
if (settings.kind().equals(GapicRetrySettings.Kind.FULL)) {
Preconditions.checkState(
retryPolicy.hasInitialBackoff(),
String.format("initialBackoff not found for setting %s", settingsName));
settingsBuilderExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(settingsBuilderExpr)
.setMethodName("setInitialRetryDelay")
.setArguments(
durationMillisMethodFn.apply(
durationToMillisValExprFn.apply(retryPolicy.getInitialBackoff())))
.build();

settingsBuilderExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(settingsBuilderExpr)
.setMethodName("setRetryDelayMultiplier")
.setArguments(floatToValExprFn.apply(retryPolicy.getBackoffMultiplier()))
.build();

Preconditions.checkState(
retryPolicy.hasMaxBackoff(),
String.format("maxBackoff not found for setting %s", settingsName));
settingsBuilderExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(settingsBuilderExpr)
.setMethodName("setMaxRetryDelay")
.setArguments(
durationMillisMethodFn.apply(
durationToMillisValExprFn.apply(retryPolicy.getMaxBackoff())))
.build();
}

if (!settings.kind().equals(GapicRetrySettings.Kind.NONE)) {
settingsBuilderExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(settingsBuilderExpr)
.setMethodName("setInitialRpcTimeout")
.setArguments(
durationMillisMethodFn.apply(durationToMillisValExprFn.apply(settings.timeout())))
.build();
}

// This will always be done, no matter the type of the retry settings object.
settingsBuilderExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(settingsBuilderExpr)
.setMethodName("setRpcTimeoutMultiplier")
.setArguments(
ValueExpr.withValue(
PrimitiveValue.builder().setType(TypeNode.DOUBLE).setValue("1.0").build()))
.build();

if (!settings.kind().equals(GapicRetrySettings.Kind.NONE)) {
for (String setterMethodName : Arrays.asList("setMaxRpcTimeout", "setTotalTimeout")) {
settingsBuilderExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(settingsBuilderExpr)
.setMethodName(setterMethodName)
.setArguments(
durationMillisMethodFn.apply(
durationToMillisValExprFn.apply(settings.timeout())))
.build();
}
}

settingsBuilderExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(settingsBuilderExpr)
.setMethodName("build")
.setReturnType(settingsVarExpr.type())
.build();

Expr settingsAssignExpr =
AssignmentExpr.builder()
.setVariableExpr(settingsVarExpr)
.setValueExpr(settingsBuilderExpr)
.build();

Expr definitionsPutExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(definitionsVarExpr)
.setMethodName("put")
.setArguments(
ValueExpr.withValue(StringObjectValue.withValue(settingsName)), settingsVarExpr)
.build();

return Arrays.asList(settingsAssignExpr, definitionsPutExpr);
}

private static Map<String, TypeNode> createStaticTypes() {
List<Class> concreteClazzes =
Arrays.asList(org.threeten.bp.Duration.class, ImmutableMap.class, RetrySettings.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,11 @@ public class ServiceStubSettingsClassComposer {
private static final String PAGED_RESPONSE_FACTORY_PATTERN = "%s_PAGE_STR_FACT";
private static final String PAGED_RESPONSE_TYPE_NAME_PATTERN = "%sPagedResponse";
private static final String NESTED_BUILDER_CLASS_NAME = "Builder";

private static final String NESTED_UNARY_METHOD_SETTINGS_BUILDERS_VAR_NAME =
"unaryMethodSettingsBuilders";
private static final String NESTED_RETRYABLE_CODE_DEFINITIONS_VAR_NAME =
"RETRYABLE_CODE_DEFINITIONS";
private static final String NESTED_RETRY_PARAM_DEFINITIONS_VAR_NAME = "RETRY_PARAM_DEFINITIONS";

private static final String STUB_PATTERN = "%sStub";
private static final String SETTINGS_LITERAL = "Settings";

Expand Down Expand Up @@ -165,7 +163,8 @@ public GapicClass generate(
createClassStatements(
service, serviceConfig, methodSettingsMemberVarExprs, messageTypes, types))
.setMethods(createClassMethods(service, methodSettingsMemberVarExprs, types))
.setNestedClasses(Arrays.asList(createNestedBuilderClass(service, types)))
.setNestedClasses(
Arrays.asList(createNestedBuilderClass(service, serviceConfig, types)))
.build();
return GapicClass.create(GapicClass.Kind.STUB, classDef);
}
Expand Down Expand Up @@ -285,7 +284,6 @@ private static List<Expr> createPagingStaticAssignExprs(
// TODO(miraleung): Add a test case for several such statements.
List<Expr> descExprs = new ArrayList<>();
List<Expr> factoryExprs = new ArrayList<>();

for (Method method : service.methods()) {
if (!method.isPaged()) {
continue;
Expand All @@ -309,7 +307,6 @@ private static List<Expr> createPagingStaticAssignExprs(
Preconditions.checkState(
field != null,
String.format("Null field found for message %s", pagedResponseMessage.name()));

if (field.isRepeated()) {
// Field is currently a List-type.
Preconditions.checkState(
Expand Down Expand Up @@ -337,7 +334,6 @@ private static List<Expr> createPagingStaticAssignExprs(
.build());
String pageStrDescVarName =
String.format(PAGE_STR_DESC_PATTERN, JavaStyle.toUpperSnakeCase(method.name()));

VariableExpr pagedListDescVarExpr =
VariableExpr.withVariable(
Variable.builder().setType(pagedListDescType).setName(pageStrDescVarName).build());
Expand Down Expand Up @@ -1074,7 +1070,7 @@ private static MethodDefinition createClassConstructor(
}

private static ClassDefinition createNestedBuilderClass(
Service service, Map<String, TypeNode> types) {
Service service, GapicServiceConfig serviceConfig, Map<String, TypeNode> types) {
String thisClassName = getThisClassName(service.name());
TypeNode outerThisClassType = types.get(thisClassName);

Expand Down Expand Up @@ -1102,22 +1098,25 @@ private static ClassDefinition createNestedBuilderClass(
.setIsStatic(true)
.setName(className)
.setExtendsType(extendsType)
.setStatements(createNestedClassStatements(nestedMethodSettingsMemberVarExprs))
.setStatements(
createNestedClassStatements(service, serviceConfig, nestedMethodSettingsMemberVarExprs))
.setMethods(createNestedClassMethods(nestedMethodSettingsMemberVarExprs, types))
.build();
}

private static List<Statement> createNestedClassStatements(
Service service,
GapicServiceConfig serviceConfig,
Map<String, VariableExpr> nestedMethodSettingsMemberVarExprs) {
List<VariableExpr> varDeclExprs = new ArrayList<>();
List<Expr> exprs = new ArrayList<>();

// Declare unaryMethodSettingsBuilders.
Function<VariableExpr, VariableExpr> varDeclFn =
v -> v.toBuilder().setIsDecl(true).setScope(ScopeNode.PRIVATE).setIsFinal(true).build();
varDeclExprs.add(varDeclFn.apply(NESTED_UNARY_METHOD_SETTINGS_BUILDERS_VAR_EXPR));
exprs.add(varDeclFn.apply(NESTED_UNARY_METHOD_SETTINGS_BUILDERS_VAR_EXPR));

// Declare all the settings fields.
varDeclExprs.addAll(
exprs.addAll(
nestedMethodSettingsMemberVarExprs.values().stream()
.map(v -> varDeclFn.apply(v))
.collect(Collectors.toList()));
Expand All @@ -1131,12 +1130,23 @@ private static List<Statement> createNestedClassStatements(
.setIsStatic(true)
.setIsFinal(true)
.build();
varDeclExprs.add(varStaticDeclFn.apply(NESTED_RETRYABLE_CODE_DEFINITIONS_VAR_EXPR));
Function<Expr, Statement> exprStatementFn = e -> ExprStatement.withExpr(e);

List<Statement> statements = new ArrayList<>();
statements.addAll(
exprs.stream().map(e -> exprStatementFn.apply(e)).collect(Collectors.toList()));
statements.add(
exprStatementFn.apply((varStaticDeclFn.apply(NESTED_RETRYABLE_CODE_DEFINITIONS_VAR_EXPR))));

// Declare the RETRY_PARAM_DEFINITIONS field.
varDeclExprs.add(varStaticDeclFn.apply(NESTED_RETRY_PARAM_DEFINITIONS_VAR_EXPR));
statements.add(
exprStatementFn.apply(varStaticDeclFn.apply(NESTED_RETRY_PARAM_DEFINITIONS_VAR_EXPR)));

statements.add(
RetrySettingsComposer.createRetryParamDefinitionsBlock(
service, serviceConfig, NESTED_RETRY_PARAM_DEFINITIONS_VAR_EXPR));

return varDeclExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList());
return statements;
}

private static List<MethodDefinition> createNestedClassMethods(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,51 @@ public void paramDefinitionsBlock_noConfigsFound() {
"static {\n",
"ImmutableMap.Builder<String, RetrySettings> definitions = ImmutableMap.builder();\n",
"RetrySettings settings = null;\n",
"settings = RetrySettings.newBuilder().setRpcTimeoutMultiplier(1.0).build();\n",
"definitions.put(\"no_retry_params\", settings);\n",
"RETRY_PARAM_DEFINITIONS = definitions.build();\n",
"}\n");
assertEquals(expected, writerVisitor.write());
}

@Test
public void paramDefinitionsBlock_basic() {
// TODO(miraleung): Fill this out.
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.createRetryParamDefinitionsBlock(
service, serviceConfig, RETRY_PARAM_DEFINITIONS_VAR_EXPR);

paramDefinitionsBlock.accept(writerVisitor);
String expected =
createLines(
"static {\n",
"ImmutableMap.Builder<String, RetrySettings> definitions = ImmutableMap.builder();\n",
"RetrySettings settings = null;\n",
"settings ="
+ " RetrySettings.newBuilder().setInitialRetryDelay(Duration.ofMillis(100L)).setRetryDelayMultiplier(2.0).setMaxRetryDelay(Duration.ofMillis(3000L)).setInitialRpcTimeout(Duration.ofMillis(10000L)).setRpcTimeoutMultiplier(1.0).setMaxRpcTimeout(Duration.ofMillis(10000L)).setTotalTimeout(Duration.ofMillis(10000L)).build();\n",
"definitions.put(\"retry_policy_1_params\", settings);\n",
"settings ="
+ " RetrySettings.newBuilder().setInitialRpcTimeout(Duration.ofMillis(5000L)).setRpcTimeoutMultiplier(1.0).setMaxRpcTimeout(Duration.ofMillis(5000L)).setTotalTimeout(Duration.ofMillis(5000L)).build();\n",
"definitions.put(\"no_retry_0_params\", settings);\n",
"RETRY_PARAM_DEFINITIONS = definitions.build();\n",
"}\n");
assertEquals(expected, writerVisitor.write());
}

private static VariableExpr createRetryParamDefinitionsVarExpr() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public void generateServiceClasses() {
+ "import java.util.List;\n"
+ "import java.util.Objects;\n"
+ "import javax.annotation.Generated;\n"
+ "import org.threeten.bp.Duration;\n"
+ "\n"
+ "@BetaApi\n"
+ "@Generated(\"by gapic-generator-java\")\n"
Expand Down Expand Up @@ -354,6 +355,32 @@ public void generateServiceClasses() {
+ " private static final ImmutableMap<String, RetrySettings>"
+ " RETRY_PARAM_DEFINITIONS;\n"
+ "\n"
+ " static {\n"
+ " ImmutableMap.Builder<String, RetrySettings> definitions ="
+ " ImmutableMap.builder();\n"
+ " RetrySettings settings = null;\n"
+ " settings =\n"
+ " RetrySettings.newBuilder()\n"
+ " .setInitialRetryDelay(Duration.ofMillis(100L))\n"
+ " .setRetryDelayMultiplier(2.0)\n"
+ " .setMaxRetryDelay(Duration.ofMillis(3000L))\n"
+ " .setInitialRpcTimeout(Duration.ofMillis(10000L))\n"
+ " .setRpcTimeoutMultiplier(1.0)\n"
+ " .setMaxRpcTimeout(Duration.ofMillis(10000L))\n"
+ " .setTotalTimeout(Duration.ofMillis(10000L))\n"
+ " .build();\n"
+ " definitions.put(\"retry_policy_1_params\", settings);\n"
+ " settings =\n"
+ " RetrySettings.newBuilder()\n"
+ " .setInitialRpcTimeout(Duration.ofMillis(5000L))\n"
+ " .setRpcTimeoutMultiplier(1.0)\n"
+ " .setMaxRpcTimeout(Duration.ofMillis(5000L))\n"
+ " .setTotalTimeout(Duration.ofMillis(5000L))\n"
+ " .build();\n"
+ " definitions.put(\"no_retry_0_params\", settings);\n"
+ " RETRY_PARAM_DEFINITIONS = definitions.build();\n"
+ " }\n"
+ "\n"
+ " protected Builder() {\n"
+ " this(((ClientContext) null));\n"
+ " }\n"
Expand Down