Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support explicit dynamic routing header #887

Merged
merged 12 commits into from
Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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 @@ -51,7 +51,6 @@
import com.google.api.generator.engine.ast.VariableExpr;
import com.google.api.generator.gapic.composer.comment.StubCommentComposer;
import com.google.api.generator.gapic.composer.store.TypeStore;
import com.google.api.generator.gapic.composer.utils.ClassNames;
import com.google.api.generator.gapic.composer.utils.PackageChecker;
import com.google.api.generator.gapic.model.GapicClass;
import com.google.api.generator.gapic.model.GapicClass.Kind;
Expand Down Expand Up @@ -204,15 +203,15 @@ public GapicClass generate(GapicContext context, Service service) {
.setName(className)
.setExtendsType(
typeStore.get(getTransportContext().classNames().getServiceStubClassName(service)))
.setStatements(classStatements)
.setMethods(
createClassMethods(
context,
service,
typeStore,
classMemberVarExprs,
callableClassMemberVarExprs,
protoMethodNameToDescriptorVarExprs))
protoMethodNameToDescriptorVarExprs, classStatements))
.setStatements(classStatements)
.build();
return GapicClass.create(kind, classDef);
}
Expand Down Expand Up @@ -249,7 +248,8 @@ protected List<MethodDefinition> createOperationsStubGetterMethod(
}

protected abstract Expr createTransportSettingsInitExpr(
Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr);
Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr,
List<Statement> classStatements);

protected List<MethodDefinition> createGetMethodDescriptorsMethod(
Service service,
Expand Down Expand Up @@ -430,7 +430,8 @@ protected List<MethodDefinition> createClassMethods(
TypeStore typeStore,
Map<String, VariableExpr> classMemberVarExprs,
Map<String, VariableExpr> callableClassMemberVarExprs,
Map<String, VariableExpr> protoMethodNameToDescriptorVarExprs) {
Map<String, VariableExpr> protoMethodNameToDescriptorVarExprs,
List<Statement> classStatements) {
List<MethodDefinition> javaMethods = new ArrayList<>();
javaMethods.addAll(createStaticCreatorMethods(service, typeStore, "newBuilder"));
javaMethods.addAll(
Expand All @@ -440,7 +441,8 @@ protected List<MethodDefinition> createClassMethods(
typeStore,
classMemberVarExprs,
callableClassMemberVarExprs,
protoMethodNameToDescriptorVarExprs));
protoMethodNameToDescriptorVarExprs,
classStatements));
javaMethods.addAll(
createGetMethodDescriptorsMethod(service, typeStore, protoMethodNameToDescriptorVarExprs));
javaMethods.addAll(
Expand Down Expand Up @@ -541,7 +543,8 @@ protected List<MethodDefinition> createConstructorMethods(
TypeStore typeStore,
Map<String, VariableExpr> classMemberVarExprs,
Map<String, VariableExpr> callableClassMemberVarExprs,
Map<String, VariableExpr> protoMethodNameToDescriptorVarExprs) {
Map<String, VariableExpr> protoMethodNameToDescriptorVarExprs,
List<Statement> classStatements) {
TypeNode stubSettingsType =
typeStore.get(getTransportContext().classNames().getServiceStubSettingsClassName(service));
VariableExpr settingsVarExpr =
Expand Down Expand Up @@ -666,7 +669,7 @@ protected List<MethodDefinition> createConstructorMethods(
m,
javaStyleMethodNameToTransportSettingsVarExprs.get(
JavaStyle.toLowerCamelCase(m.name())),
protoMethodNameToDescriptorVarExprs.get(m.name())))
protoMethodNameToDescriptorVarExprs.get(m.name()), classStatements))
.collect(Collectors.toList()));
secondCtorStatements.addAll(
secondCtorExprs.stream().map(ExprStatement::withExpr).collect(Collectors.toList()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@

import com.google.api.gax.grpc.GrpcCallSettings;
import com.google.api.gax.grpc.GrpcStubCallableFactory;
import com.google.api.gax.grpc.RoutingHeaderParamsBuilder;
import com.google.api.generator.engine.ast.AssignmentExpr;
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.LambdaExpr;
import com.google.api.generator.engine.ast.MethodInvocationExpr;
import com.google.api.generator.engine.ast.NewObjectExpr;
import com.google.api.generator.engine.ast.ScopeNode;
import com.google.api.generator.engine.ast.Statement;
import com.google.api.generator.engine.ast.StringObjectValue;
Expand All @@ -35,9 +37,11 @@
import com.google.api.generator.gapic.model.HttpBindings.HttpBinding;
import com.google.api.generator.gapic.model.Message;
import com.google.api.generator.gapic.model.Method;
import com.google.api.generator.gapic.model.RoutingHeaders.RoutingHeader;
import com.google.api.generator.gapic.model.Service;
import com.google.api.generator.gapic.utils.JavaStyle;
import com.google.common.base.Preconditions;
import com.google.api.pathtemplate.PathTemplate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.longrunning.stub.GrpcOperationsStub;
import io.grpc.MethodDescriptor;
Expand All @@ -53,6 +57,7 @@
import java.util.stream.Collectors;

public class GrpcServiceStubClassComposer extends AbstractTransportServiceStubClassComposer {

private static final GrpcServiceStubClassComposer INSTANCE = new GrpcServiceStubClassComposer();

// Legacy support for the original reroute_to_grpc_interface option in gapic.yaml. These two APIs
Expand Down Expand Up @@ -194,7 +199,10 @@ protected EnumRefExpr getMethodDescriptorMethodTypeExpr(Method protoMethod) {

@Override
protected Expr createTransportSettingsInitExpr(
Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr) {
Method method,
VariableExpr transportSettingsVarExpr,
VariableExpr methodDescriptorVarExpr,
List<Statement> classStatements) {
MethodInvocationExpr callSettingsBuilderExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(getTransportContext().transportCallSettingsType())
Expand All @@ -208,12 +216,12 @@ protected Expr createTransportSettingsInitExpr(
.setArguments(Arrays.asList(methodDescriptorVarExpr))
.build();

if (method.hasHttpBindings()) {
if (method.hasHttpBindings() || method.hasRoutingHeaders()) {
callSettingsBuilderExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(callSettingsBuilderExpr)
.setMethodName("setParamsExtractor")
.setArguments(createRequestParamsExtractorClassInstance(method))
.setArguments(createRequestParamsExtractorClassInstance(method, classStatements))
.build();
}

Expand Down Expand Up @@ -245,10 +253,123 @@ protected String getProtoRpcFullMethodName(Service protoService, Method protoMet
return String.format("google.iam.v1.IAMPolicy/%s", protoMethod.name());
}

private LambdaExpr createRequestParamsExtractorClassInstance(Method method) {
Preconditions.checkState(
method.hasHttpBindings(), String.format("Method %s has no HTTP binding", method.name()));
private LambdaExpr createRequestParamsExtractorClassInstance(
Method method, List<Statement> classStatements) {
List<Expr> bodyExprs = new ArrayList<>();
VariableExpr requestVarExpr =
VariableExpr.withVariable(
Variable.builder().setType(method.inputType()).setName("request").build());
TypeNode returnType =
TypeNode.withReference(
ConcreteReference.builder()
.setClazz(Map.class)
.setGenerics(TypeNode.STRING.reference(), TypeNode.STRING.reference())
.build());
Expr returnExpr;
// If the google.api.routing annotation is present(even with empty routing parameters),
// the implicit routing headers specified in the google.api.http annotation should not be sent
if (method.routingHeaders() == null) {
returnExpr = addRequestParamsForHttpBindings(method, bodyExprs, requestVarExpr, returnType);
} else {
returnExpr =
addRequestParamsForRoutingHeaders(
method, classStatements, bodyExprs, requestVarExpr, returnType);
}

// Overrides extract().
// https://github.com/googleapis/gax-java/blob/8d45d186e36ae97b789a6f89d80ae5213a773b65/gax/src/main/java/com/google/api/gax/rpc/RequestParamsExtractor.java#L55
return LambdaExpr.builder()
.setArguments(requestVarExpr.toBuilder().setIsDecl(true).build())
.setBody(
bodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()))
.setReturnExpr(returnExpr)
.build();
}

private Expr addRequestParamsForRoutingHeaders(
blakeli0 marked this conversation as resolved.
Show resolved Hide resolved
Method method,
List<Statement> classStatements,
List<Expr> bodyExprs,
VariableExpr requestVarExpr,
TypeNode returnType) {
TypeNode routingHeadersBuilderType =
TypeNode.withReference(
ConcreteReference.builder().setClazz(RoutingHeaderParamsBuilder.class).build());
VariableExpr routingHeadersBuilderVarExpr =
VariableExpr.builder()
.setVariable(
Variable.builder().setName("builder").setType(routingHeadersBuilderType).build())
.setIsDecl(true)
.build();
Expr newBuilderExpr = NewObjectExpr.builder().setType(routingHeadersBuilderType).build();
Expr newRoutingHeadersAssignExpr =
AssignmentExpr.builder()
.setVariableExpr(routingHeadersBuilderVarExpr)
.setValueExpr(newBuilderExpr)
.build();
bodyExprs.add(newRoutingHeadersAssignExpr);
ImmutableList<RoutingHeader> routingHeaders = method.routingHeaders().routingHeadersList();
blakeli0 marked this conversation as resolved.
Show resolved Hide resolved
VariableExpr routingHeadersBuilderVarNonDeclExpr =
VariableExpr.builder()
.setVariable(
Variable.builder().setName("builder").setType(routingHeadersBuilderType).build())
.build();
for (int i = 0; i < routingHeaders.size(); i++) {
RoutingHeader routingHeader = routingHeaders.get(i);
MethodInvocationExpr requestFieldGetterExpr =
createRequestFieldGetterExpr(requestVarExpr, routingHeader.fieldName());
Expr routingHeaderKeyExpr =
ValueExpr.withValue(StringObjectValue.withValue(routingHeader.name()));
// TODO: Create proper snake style upper case name
blakeli0 marked this conversation as resolved.
Show resolved Hide resolved
String pathTemplateName =
String.format("PATH_TEMPLATE_%s_%s", method.name().toUpperCase(), i);
TypeNode pathTemplateType =
TypeNode.withReference(ConcreteReference.withClazz(PathTemplate.class));
Variable pathTemplateVar =
Variable.builder().setType(pathTemplateType).setName(pathTemplateName).build();
Expr routingHeaderPatternExpr = VariableExpr.withVariable(pathTemplateVar);
VariableExpr pathTemplateVarExpr =
VariableExpr.builder()
.setVariable(pathTemplateVar)
.setIsDecl(true)
.setIsStatic(true)
.setIsFinal(true)
.setScope(ScopeNode.PRIVATE)
.build();
ValueExpr valueExpr =
ValueExpr.withValue(StringObjectValue.withValue(routingHeader.pattern()));
Expr pathTemplateExpr =
AssignmentExpr.builder()
.setVariableExpr(pathTemplateVarExpr)
.setValueExpr(
MethodInvocationExpr.builder()
.setStaticReferenceType(pathTemplateType)
.setMethodName("create")
.setArguments(valueExpr)
.setReturnType(pathTemplateType)
.build())
.build();
Statement pathTemplateClassVar = ExprStatement.withExpr(pathTemplateExpr);
classStatements.add(pathTemplateClassVar);
MethodInvocationExpr addParamsMethodExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(routingHeadersBuilderVarNonDeclExpr)
.setMethodName("add")
.setArguments(requestFieldGetterExpr, routingHeaderKeyExpr, routingHeaderPatternExpr)
.build();

bodyExprs.add(addParamsMethodExpr);
}

return MethodInvocationExpr.builder()
.setExprReferenceExpr(routingHeadersBuilderVarNonDeclExpr)
.setMethodName("build")
.setReturnType(returnType)
.build();
}

private Expr addRequestParamsForHttpBindings(
Method method, List<Expr> bodyExprs, VariableExpr requestVarExpr, TypeNode returnType) {
TypeNode paramsVarType =
TypeNode.withReference(
ConcreteReference.builder()
Expand All @@ -269,32 +390,11 @@ private LambdaExpr createRequestParamsExtractorClassInstance(Method method) {
.setReturnType(paramsVarType)
.build())
.build();
List<Expr> bodyExprs = new ArrayList<>();
bodyExprs.add(paramsAssignExpr);

VariableExpr requestVarExpr =
VariableExpr.withVariable(
Variable.builder().setType(method.inputType()).setName("request").build());

for (HttpBinding httpBindingFieldBinding : method.httpBindings().pathParameters()) {
// Handle foo.bar cases by descending into the subfields.
MethodInvocationExpr.Builder requestFieldGetterExprBuilder =
MethodInvocationExpr.builder().setExprReferenceExpr(requestVarExpr);
String[] descendantFields = httpBindingFieldBinding.name().split("\\.");
for (int i = 0; i < descendantFields.length; i++) {
String currFieldName = descendantFields[i];
String bindingFieldMethodName =
String.format("get%s", JavaStyle.toUpperCamelCase(currFieldName));
requestFieldGetterExprBuilder =
requestFieldGetterExprBuilder.setMethodName(bindingFieldMethodName);
if (i < descendantFields.length - 1) {
requestFieldGetterExprBuilder =
MethodInvocationExpr.builder()
.setExprReferenceExpr(requestFieldGetterExprBuilder.build());
}
}

MethodInvocationExpr requestBuilderExpr = requestFieldGetterExprBuilder.build();
MethodInvocationExpr requestBuilderExpr =
createRequestFieldGetterExpr(requestVarExpr, httpBindingFieldBinding.name());
Expr valueOfExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(TypeNode.STRING)
Expand All @@ -313,26 +413,32 @@ private LambdaExpr createRequestParamsExtractorClassInstance(Method method) {
bodyExprs.add(paramsPutExpr);
}

TypeNode returnType =
TypeNode.withReference(
ConcreteReference.builder()
.setClazz(Map.class)
.setGenerics(TypeNode.STRING.reference(), TypeNode.STRING.reference())
.build());
Expr returnExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(paramsVarExpr)
.setMethodName("build")
.setReturnType(returnType)
.build();

// Overrides extract().
// https://github.com/googleapis/gax-java/blob/8d45d186e36ae97b789a6f89d80ae5213a773b65/gax/src/main/java/com/google/api/gax/rpc/RequestParamsExtractor.java#L55
return LambdaExpr.builder()
.setArguments(requestVarExpr.toBuilder().setIsDecl(true).build())
.setBody(
bodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()))
.setReturnExpr(returnExpr)
return MethodInvocationExpr.builder()
.setExprReferenceExpr(paramsVarExpr)
.setMethodName("build")
.setReturnType(returnType)
.build();
}

private MethodInvocationExpr createRequestFieldGetterExpr(
VariableExpr requestVarExpr, String fieldName) {
MethodInvocationExpr.Builder requestFieldGetterExprBuilder =
MethodInvocationExpr.builder().setExprReferenceExpr(requestVarExpr);
String[] descendantFields = fieldName.split("\\.");
// Handle foo.bar cases by descending into the subfields.
// e.g. foo.bar -> request.getFoo().getBar()
for (int i = 0; i < descendantFields.length; i++) {
String currFieldName = descendantFields[i];
String bindingFieldMethodName =
String.format("get%s", JavaStyle.toUpperCamelCase(currFieldName));
requestFieldGetterExprBuilder =
requestFieldGetterExprBuilder.setMethodName(bindingFieldMethodName);
if (i < descendantFields.length - 1) {
requestFieldGetterExprBuilder =
MethodInvocationExpr.builder()
.setExprReferenceExpr(requestFieldGetterExprBuilder.build());
}
}
return requestFieldGetterExprBuilder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,10 @@ protected List<MethodDefinition> createOperationsStubGetterMethod(

@Override
protected Expr createTransportSettingsInitExpr(
Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr) {
Method method,
VariableExpr transportSettingsVarExpr,
VariableExpr methodDescriptorVarExpr,
List<Statement> classStatements) {
MethodInvocationExpr callSettingsBuilderExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(
Expand Down
Loading