Skip to content

Commit

Permalink
#869. Move the logic of match-and-extract to GAX. Create path templat…
Browse files Browse the repository at this point in the history
…es on code generation time not runtime.
  • Loading branch information
blakeli0 committed Jan 6, 2022
1 parent f375d04 commit 14c92f8
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 104 deletions.
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,6 +16,7 @@

import com.google.api.gax.grpc.GrpcCallSettings;
import com.google.api.gax.grpc.GrpcStubCallableFactory;
import com.google.api.gax.rpc.internal.RoutingHeaderHelper;
import com.google.api.generator.engine.ast.AssignmentExpr;
import com.google.api.generator.engine.ast.ConcreteReference;
import com.google.api.generator.engine.ast.EnumRefExpr;
Expand All @@ -35,15 +36,13 @@
import com.google.api.generator.engine.ast.VariableExpr;
import com.google.api.generator.gapic.composer.common.AbstractTransportServiceStubClassComposer;
import com.google.api.generator.gapic.composer.store.TypeStore;
import com.google.api.generator.gapic.model.GapicContext;
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.api.pathtemplate.PathTemplate;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.longrunning.stub.GrpcOperationsStub;
Expand Down Expand Up @@ -202,7 +201,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 @@ -216,12 +218,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 All @@ -237,27 +239,7 @@ protected Expr createTransportSettingsInitExpr(
.build();
}

@Override
protected List<MethodDefinition> createClassMethods(
GapicContext context,
Service service,
TypeStore typeStore,
Map<String, VariableExpr> classMemberVarExprs,
Map<String, VariableExpr> callableClassMemberVarExprs,
Map<String, VariableExpr> protoMethodNameToDescriptorVarExprs) {
List<MethodDefinition> classMethods =
super.createClassMethods(
context,
service,
typeStore,
classMemberVarExprs,
callableClassMemberVarExprs,
protoMethodNameToDescriptorVarExprs);
// TODO: need a way to check do we need to create this method or not, or make it an inner method
classMethods.add(createAddParamsMethod());
return classMethods;
}

// TODO: remove this method once we finalized the approach, keep it as a reference for now.
private MethodDefinition createAddParamsMethod() {
TypeNode paramsVarType =
TypeNode.withReference(
Expand Down Expand Up @@ -408,9 +390,8 @@ 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) {

TypeNode paramsVarType =
TypeNode.withReference(
Expand Down Expand Up @@ -439,52 +420,10 @@ private LambdaExpr createRequestParamsExtractorClassInstance(Method method) {
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 requestBuilderExpr =
createRequestFieldGetterExpr(requestVarExpr, httpBindingFieldBinding.name());

Expr valueOfExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(TypeNode.STRING)
.setMethodName("valueOf")
.setArguments(requestBuilderExpr)
.build();

// Comment out for now. TODO: completely remove this part if routing headers is not null?
// Are these params used for anything else other than implicit dynamic routing?
// Expr paramsPutExpr =
// MethodInvocationExpr.builder()
// .setExprReferenceExpr(paramsVarExpr)
// .setMethodName("put")
// .setArguments(
//
// ValueExpr.withValue(StringObjectValue.withValue(httpBindingFieldBinding.name())),
// valueOfExpr)
// .build();
// bodyExprs.add(paramsPutExpr);
}

for (RoutingHeader routingHeader : method.routingHeaders().routingHeadersList()) {
MethodInvocationExpr requestFieldGetterExpr =
createRequestFieldGetterExpr(requestVarExpr, routingHeader.field());
addRequestParamsForHttpBindings(method, paramsVarExpr, bodyExprs, requestVarExpr);

Expr routingHeaderKeyExpr =
ValueExpr.withValue(StringObjectValue.withValue(routingHeader.name()));
Expr routingHeaderPatternExpr =
ValueExpr.withValue(StringObjectValue.withValue(routingHeader.pattern()));
MethodInvocationExpr addParamsMethodExpr =
MethodInvocationExpr.builder()
.setMethodName("addParams")
.setArguments(
paramsVarExpr,
requestFieldGetterExpr,
routingHeaderKeyExpr,
routingHeaderPatternExpr)
.build();

bodyExprs.add(addParamsMethodExpr);
}
addRequestParamsForRoutingHeders(
method, classStatements, paramsVarExpr, bodyExprs, requestVarExpr);

TypeNode returnType =
TypeNode.withReference(
Expand All @@ -509,11 +448,107 @@ private LambdaExpr createRequestParamsExtractorClassInstance(Method method) {
.build();
}

private void addRequestParamsForRoutingHeders(
Method method,
List<Statement> classStatements,
VariableExpr paramsVarExpr,
List<Expr> bodyExprs,
VariableExpr requestVarExpr) {
ImmutableList<RoutingHeader> routingHeaders = method.routingHeaders().routingHeadersList();
for (int i = 0; i < routingHeaders.size(); i++) {
RoutingHeader routingHeader = routingHeaders.get(i);
MethodInvocationExpr requestFieldGetterExpr =
createRequestFieldGetterExpr(requestVarExpr, routingHeader.field());
Expr routingHeaderKeyExpr =
ValueExpr.withValue(StringObjectValue.withValue(routingHeader.name()));
// TODO: Create proper snake style upper case name
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()
.setStaticReferenceType(
TypeNode.withReference(ConcreteReference.withClazz(RoutingHeaderHelper.class)))
.setMethodName("addParams")
.setArguments(
paramsVarExpr,
requestFieldGetterExpr,
routingHeaderKeyExpr,
routingHeaderPatternExpr)
.build();

bodyExprs.add(addParamsMethodExpr);
}
}

private void addRequestParamsForHttpBindings(
Method method,
VariableExpr paramsVarExpr,
List<Expr> bodyExprs,
VariableExpr requestVarExpr) {
// TODO: Are these params used for anything else other than implicit dynamic routing?
// Can we skip this method if routing headers are configured?
if (!method.routingHeaders().routingHeadersList().isEmpty()) {
return;
}
for (HttpBinding httpBindingFieldBinding : method.httpBindings().pathParameters()) {
// Handle foo.bar cases by descending into the subfields.
MethodInvocationExpr requestBuilderExpr =
createRequestFieldGetterExpr(requestVarExpr, httpBindingFieldBinding.name());

Expr valueOfExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(TypeNode.STRING)
.setMethodName("valueOf")
.setArguments(requestBuilderExpr)
.build();

Expr paramsPutExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(paramsVarExpr)
.setMethodName("put")
.setArguments(
ValueExpr.withValue(StringObjectValue.withValue(httpBindingFieldBinding.name())),
valueOfExpr)
.build();
bodyExprs.add(paramsPutExpr);
}
}

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 =
Expand Down
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
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ public boolean hasHttpBindings() {
return httpBindings() != null && !httpBindings().pathParameters().isEmpty();
}

public boolean hasRoutingHeaders() {
return routingHeaders() != null && !routingHeaders().routingHeadersList().isEmpty();
}

public boolean isMixin() {
return mixedInApiName() != null;
}
Expand Down
Loading

0 comments on commit 14c92f8

Please sign in to comment.