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

[samplecode][1/3]Implement Pure Unary RPC sample code #573

Merged
merged 21 commits into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ public static List<GapicClass> generateServiceClasses(
@Nonnull Map<String, ResourceName> resourceNames,
@Nonnull Map<String, Message> messageTypes) {
List<GapicClass> clazzes = new ArrayList<>();
clazzes.addAll(generateStubClasses(service, serviceConfig, messageTypes));
clazzes.addAll(generateClientSettingsClasses(service, messageTypes));
clazzes.addAll(generateStubClasses(service, serviceConfig, messageTypes, resourceNames));
clazzes.addAll(generateClientSettingsClasses(service, messageTypes, resourceNames));
clazzes.addAll(generateMocksAndTestClasses(service, resourceNames, messageTypes));
// TODO(miraleung): Generate test classes.
return clazzes;
Expand All @@ -76,7 +76,10 @@ public static List<GapicClass> generateResourceNameHelperClasses(
}

public static List<GapicClass> generateStubClasses(
Service service, GapicServiceConfig serviceConfig, Map<String, Message> messageTypes) {
Service service,
GapicServiceConfig serviceConfig,
Map<String, Message> messageTypes,
Map<String, ResourceName> resourceNames) {
List<GapicClass> clazzes = new ArrayList<>();
clazzes.add(ServiceStubClassComposer.instance().generate(service, messageTypes));
clazzes.add(
Expand All @@ -87,9 +90,10 @@ public static List<GapicClass> generateStubClasses(
}

public static List<GapicClass> generateClientSettingsClasses(
Service service, Map<String, Message> messageTypes) {
Service service, Map<String, Message> messageTypes, Map<String, ResourceName> resourceNames) {
List<GapicClass> clazzes = new ArrayList<>();
clazzes.add(ServiceClientClassComposer.instance().generate(service, messageTypes));
clazzes.add(
ServiceClientClassComposer.instance().generate(service, messageTypes, resourceNames));
clazzes.add(ServiceSettingsClassComposer.instance().generate(service, messageTypes));
return clazzes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import com.google.api.generator.gapic.model.Method;
import com.google.api.generator.gapic.model.Method.Stream;
import com.google.api.generator.gapic.model.MethodArgument;
import com.google.api.generator.gapic.model.ResourceName;
import com.google.api.generator.gapic.model.Service;
import com.google.api.generator.gapic.utils.JavaStyle;
import com.google.common.annotations.VisibleForTesting;
Expand All @@ -79,12 +80,13 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Generated;

public class ServiceClientClassComposer implements ClassComposer {
public class ServiceClientClassComposer {
private static final ServiceClientClassComposer INSTANCE = new ServiceClientClassComposer();
private static final String PAGED_RESPONSE_TYPE_NAME_PATTERN = "%sPagedResponse";
private static final String CALLABLE_NAME_PATTERN = "%sCallable";
Expand All @@ -108,8 +110,8 @@ public static ServiceClientClassComposer instance() {
return INSTANCE;
}

@Override
public GapicClass generate(Service service, Map<String, Message> messageTypes) {
public GapicClass generate(
Service service, Map<String, Message> messageTypes, Map<String, ResourceName> resourceNames) {
Map<String, TypeNode> types = createTypes(service, messageTypes);
String className = getClientClassName(service);
GapicClass.Kind kind = Kind.MAIN;
Expand All @@ -129,7 +131,8 @@ public GapicClass generate(Service service, Map<String, Message> messageTypes) {
.setName(className)
.setImplementsTypes(createClassImplements(types))
.setStatements(createFieldDeclarations(service, types, hasLroClient))
.setMethods(createClassMethods(service, messageTypes, types, hasLroClient))
.setMethods(
createClassMethods(service, messageTypes, types, resourceNames, hasLroClient))
.setNestedClasses(createNestedPagingClasses(service, messageTypes, types))
.build();
return GapicClass.create(kind, classDef);
Expand All @@ -152,12 +155,13 @@ private static List<MethodDefinition> createClassMethods(
Service service,
Map<String, Message> messageTypes,
Map<String, TypeNode> types,
Map<String, ResourceName> resourceNames,
boolean hasLroClient) {
List<MethodDefinition> methods = new ArrayList<>();
methods.addAll(createStaticCreatorMethods(service, types));
methods.addAll(createConstructorMethods(service, types, hasLroClient));
methods.addAll(createGetterMethods(service, types, hasLroClient));
methods.addAll(createServiceMethods(service, messageTypes, types));
methods.addAll(createServiceMethods(service, messageTypes, types, resourceNames));
methods.addAll(createBackgroundResourceMethods(service, types));
return methods;
}
Expand Down Expand Up @@ -471,11 +475,16 @@ private static List<MethodDefinition> createGetterMethods(
}

private static List<MethodDefinition> createServiceMethods(
Service service, Map<String, Message> messageTypes, Map<String, TypeNode> types) {
Service service,
Map<String, Message> messageTypes,
Map<String, TypeNode> types,
Map<String, ResourceName> resourceNames) {
List<MethodDefinition> javaMethods = new ArrayList<>();
for (Method method : service.methods()) {
if (method.stream().equals(Stream.NONE)) {
javaMethods.addAll(createMethodVariants(method, messageTypes, types));
javaMethods.addAll(
createMethodVariants(
method, getClientClassName(service), messageTypes, types, resourceNames));
javaMethods.add(createMethodDefaultMethod(method, types));
}
if (method.hasLro()) {
Expand All @@ -490,7 +499,11 @@ private static List<MethodDefinition> createServiceMethods(
}

private static List<MethodDefinition> createMethodVariants(
Method method, Map<String, Message> messageTypes, Map<String, TypeNode> types) {
Method method,
String clientName,
Map<String, Message> messageTypes,
Map<String, TypeNode> types,
Map<String, ResourceName> resourceNames) {
List<MethodDefinition> javaMethods = new ArrayList<>();
String methodName = JavaStyle.toLowerCamelCase(method.name());
TypeNode methodInputType = method.inputType();
Expand Down Expand Up @@ -552,10 +565,20 @@ private static List<MethodDefinition> createMethodVariants(
.setReturnType(methodOutputType)
.build();

Optional<String> methodSampleCode = Optional.empty();
if (!method.isPaged() && !method.hasLro()) {
// TODO(summerji): Remove the condition check once finished the implementation on paged
// sample code and lro sample code.
methodSampleCode =
Optional.of(
ServiceClientSampleCodeComposer.composeRpcMethodHeaderSampleCode(
method, types.get(clientName), signature, resourceNames));
}
MethodDefinition.Builder methodVariantBuilder =
MethodDefinition.builder()
.setHeaderCommentStatements(
ServiceClientCommentComposer.createRpcMethodHeaderComment(method, signature))
ServiceClientCommentComposer.createRpcMethodHeaderComment(
method, signature, methodSampleCode))
.setScope(ScopeNode.PUBLIC)
.setIsFinal(true)
.setName(String.format(method.hasLro() ? "%sAsync" : "%s", methodName))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -162,16 +163,18 @@ static CommentStatement createCreateMethodStubArgComment(
}

static List<CommentStatement> createRpcMethodHeaderComment(
Method method, List<MethodArgument> methodArguments) {
Method method, List<MethodArgument> methodArguments, Optional<String> sampleCode) {
JavaDocComment.Builder methodJavadocBuilder = JavaDocComment.builder();

if (method.hasDescription()) {
methodJavadocBuilder =
processProtobufComment(method.description(), methodJavadocBuilder, null);
}

// methodJavadocBuilder.addParagraph(METHOD_DESCRIPTION_SAMPLE_CODE_SUMMARY_STRING);
// TODO(summerji): Add sample code here and uncomment the above.
if (sampleCode.isPresent()) {
methodJavadocBuilder.addParagraph(METHOD_DESCRIPTION_SAMPLE_CODE_SUMMARY_STRING);
methodJavadocBuilder.addSampleCode(sampleCode.get());
}

if (methodArguments.isEmpty()) {
methodJavadocBuilder.addParam(
Expand All @@ -196,7 +199,8 @@ static List<CommentStatement> createRpcMethodHeaderComment(
}

static List<CommentStatement> createRpcMethodHeaderComment(Method method) {
return createRpcMethodHeaderComment(method, Collections.emptyList());
// TODO(summerji): Refactor this method when implement default method sample code.
return createRpcMethodHeaderComment(method, Collections.emptyList(), Optional.empty());
}

static CommentStatement createMethodNoArgComment(String serviceName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,29 @@
import com.google.api.generator.engine.ast.Expr;
import com.google.api.generator.engine.ast.ExprStatement;
import com.google.api.generator.engine.ast.MethodInvocationExpr;
import com.google.api.generator.engine.ast.TryCatchStatement;
import com.google.api.generator.engine.ast.TypeNode;
import com.google.api.generator.engine.ast.VaporReference;
import com.google.api.generator.engine.ast.Variable;
import com.google.api.generator.engine.ast.VariableExpr;
import com.google.api.generator.gapic.composer.samplecode.SampleCodeWriter;
import com.google.api.generator.gapic.model.Method;
import com.google.api.generator.gapic.model.MethodArgument;
import com.google.api.generator.gapic.model.ResourceName;
import com.google.api.generator.gapic.utils.JavaStyle;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class ServiceClientSampleCodeComposer {
// TODO(summerji): Add unit tests for ServiceClientSampleCodeComposer.

public static String composeClassHeaderCredentialsSampleCode(
// TODO(summerji): Add unit tests for composeClassHeaderCredentialsSampleCode.
TypeNode clientType, TypeNode settingsType) {
// Initialize clientSettings with builder() method.
// e.g. EchoSettings echoSettings =
Expand Down Expand Up @@ -105,6 +116,7 @@ public static String composeClassHeaderCredentialsSampleCode(
}

public static String composeClassHeaderEndpointSampleCode(
// TODO(summerji): Add unit tests for composeClassHeaderEndpointSampleCode.
TypeNode clientType, TypeNode settingsType) {
// Initialize client settings with builder() method.
// e.g. EchoSettings echoSettings = EchoSettings.newBuilder().setEndpoint("myEndpoint").build();
Expand Down Expand Up @@ -169,4 +181,141 @@ public static String composeClassHeaderEndpointSampleCode(
ExprStatement.withExpr(initSettingsVarExpr),
ExprStatement.withExpr(initClientVarExpr)));
}

public static String composeRpcMethodHeaderSampleCode(
Method method,
summer-ji-eng marked this conversation as resolved.
Show resolved Hide resolved
TypeNode clientType,
List<MethodArgument> arguments,
Map<String, ResourceName> resourceNames) {
// TODO(summerji): Add other types RPC methods' sample code.
return SampleCodeWriter.write(
composeUnaryRpcMethodSampleCode(method, clientType, arguments, resourceNames));
}

@VisibleForTesting
static TryCatchStatement composeUnaryRpcMethodSampleCode(
Method method,
TypeNode clientType,
List<MethodArgument> arguments,
Map<String, ResourceName> resourceNames) {
VariableExpr clientVarExpr =
VariableExpr.withVariable(
Variable.builder()
.setName(JavaStyle.toLowerCamelCase(clientType.reference().name()))
.setType(clientType)
.build());
// List of rpc method arguments' variable expressions.
List<VariableExpr> rpcMethodArgVarExprs =
arguments.stream()
.map(
arg ->
VariableExpr.withVariable(
Variable.builder()
.setName(JavaStyle.toLowerCamelCase(arg.name()))
.setType(arg.type())
.build()))
.collect(Collectors.toList());
// List of rpc method arguments' default value expression.
List<ResourceName> resourceNameList =
resourceNames.values().stream().collect(Collectors.toList());
List<Expr> rpcMethodArgDefaultValueExprs =
arguments.stream()
.map(
arg ->
!isStringTypedResourceName(arg, resourceNames)
? DefaultValueComposer.createDefaultValue(arg, resourceNames)
: MethodInvocationExpr.builder()
.setExprReferenceExpr(
DefaultValueComposer.createDefaultValue(
resourceNames.get(
arg.field().resourceReference().resourceTypeString()),
resourceNameList,
arg.field().name()))
.setMethodName("toString")
.setReturnType(TypeNode.STRING)
.build())
.collect(Collectors.toList());

List<Expr> bodyExprs = new ArrayList<>();
Preconditions.checkState(
rpcMethodArgVarExprs.size() == rpcMethodArgDefaultValueExprs.size(),
"Expected the number of method arguments to match the number of default values.");
bodyExprs.addAll(
IntStream.range(0, rpcMethodArgVarExprs.size())
.mapToObj(
i ->
AssignmentExpr.builder()
.setVariableExpr(
(rpcMethodArgVarExprs.get(i)).toBuilder().setIsDecl(true).build())
.setValueExpr(rpcMethodArgDefaultValueExprs.get(i))
.build())
.collect(Collectors.toList()));
// Invoke current method based on return type.
// e.g. if return void, echoClient.echo(..); or,
// e.g. if return other type, EchoResponse response = echoClient.echo(...);
boolean returnsVoid = isProtoEmptyType(method.outputType());
if (returnsVoid) {
bodyExprs.add(
MethodInvocationExpr.builder()
.setExprReferenceExpr(clientVarExpr)
.setMethodName(JavaStyle.toLowerCamelCase(method.name()))
.setArguments(
rpcMethodArgVarExprs.stream().map(e -> (Expr) e).collect(Collectors.toList()))
.setReturnType(clientType)
.build());
} else {
VariableExpr responseVarExpr =
VariableExpr.withVariable(
Variable.builder().setName("response").setType(method.outputType()).build());
MethodInvocationExpr clientMethodInvocationExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(clientVarExpr)
.setMethodName(JavaStyle.toLowerCamelCase(method.name()))
.setArguments(
rpcMethodArgVarExprs.stream().map(e -> (Expr) e).collect(Collectors.toList()))
.setReturnType(responseVarExpr.variable().type())
.build();
bodyExprs.add(
AssignmentExpr.builder()
.setVariableExpr(responseVarExpr.toBuilder().setIsDecl(true).build())
.setValueExpr(clientMethodInvocationExpr)
.build());
}

return TryCatchStatement.builder()
.setTryResourceExpr(assignClientVariableWithCreateMethodExpr(clientVarExpr))
.setTryBody(
bodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()))
.setIsSampleCode(true)
.build();
}

// ==================================Helpers===================================================//

// Assign client variable expr with create client.
// e.g EchoClient echoClient = EchoClient.create()
private static AssignmentExpr assignClientVariableWithCreateMethodExpr(
VariableExpr clientVarExpr) {
return AssignmentExpr.builder()
.setVariableExpr(clientVarExpr.toBuilder().setIsDecl(true).build())
.setValueExpr(
MethodInvocationExpr.builder()
.setStaticReferenceType(clientVarExpr.variable().type())
.setReturnType(clientVarExpr.variable().type())
.setMethodName("create")
.build())
.build();
}

private static boolean isStringTypedResourceName(
MethodArgument arg, Map<String, ResourceName> resourceNames) {
return arg.type().equals(TypeNode.STRING)
&& arg.field().hasResourceReference()
&& resourceNames.containsKey(arg.field().resourceReference().resourceTypeString());
}

private static boolean isProtoEmptyType(TypeNode type) {
return type.reference().pakkage().equals("com.google.protobuf")
&& type.reference().name().equals("Empty");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ TESTS = UPDATE_GOLDENS_TESTS + [
"DefaultValueComposerTest",
"ResourceNameTokenizerTest",
"RetrySettingsComposerTest",
"ServiceClientSampleCodeComposerTest",
]

TEST_DEPS = [
Expand All @@ -38,6 +39,7 @@ TEST_DEPS = [
"//src/main/java/com/google/api/generator/gapic/protoparser",
"//src/test/java/com/google/api/generator/gapic/testdata:showcase_java_proto",
"//src/test/java/com/google/api/generator/gapic/testdata:testgapic_java_proto",
"@com_google_api_api_common//jar",
miraleung marked this conversation as resolved.
Show resolved Hide resolved
"@com_google_api_gax_java//gax",
"@com_google_googleapis//google/logging/v2:logging_java_proto",
"@com_google_googleapis//google/pubsub/v1:pubsub_java_proto",
Expand Down