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 @@ -806,7 +806,7 @@ private static MethodDefinition createCallableMethod(
}
// TODO (summerji): Implement sample code for stream method.
// Replace by if (method.stream()).
if (method.stream().equals(Stream.SERVER)) {
if (method.stream().equals(Stream.SERVER) || method.stream().equals(Stream.BIDI)) {
sampleCodeOpt =
Optional.of(
ServiceClientSampleCodeComposer.composeStreamCallableMethodHeaderSampleCode(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.google.api.core.ApiFuture;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.api.gax.longrunning.OperationFuture;
import com.google.api.gax.rpc.BidiStream;
import com.google.api.gax.rpc.ServerStream;
import com.google.api.generator.engine.ast.AssignmentExpr;
import com.google.api.generator.engine.ast.CommentStatement;
Expand All @@ -36,6 +37,7 @@
import com.google.api.generator.gapic.model.Field;
import com.google.api.generator.gapic.model.Message;
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.utils.JavaStyle;
Expand Down Expand Up @@ -552,8 +554,15 @@ public static String composeStreamCallableMethodHeaderSampleCode(
.build();

// TODO (summerji) : Implement Stream.Client and Stream.Bidi sample code body statements.
List<Statement> bodyStatements =
composeStreamServerSampleCodeBodyStatements(method, clientVarExpr, requestAssignmentExpr);
List<Statement> bodyStatements = new ArrayList<>();
if (method.stream().equals(Stream.SERVER)) {
bodyStatements.addAll(
composeStreamServerSampleCodeBodyStatements(
method, clientVarExpr, requestAssignmentExpr));
} else if (method.stream().equals(Stream.BIDI)) {
bodyStatements.addAll(
composeStreamBidiSampleCodeBodyStatements(method, clientVarExpr, requestAssignmentExpr));
}

return SampleCodeWriter.write(
TryCatchStatement.builder()
Expand Down Expand Up @@ -761,6 +770,79 @@ private static List<Statement> composeStreamServerSampleCodeBodyStatements(
return bodyStatements;
}

private static List<Statement> composeStreamBidiSampleCodeBodyStatements(
Method method, VariableExpr clientVarExpr, AssignmentExpr requestAssignmentExpr) {
List<Expr> bodyExprs = new ArrayList<>();

// Create bidi stream variable expression and assign it with invoking client's bidi stream
// method.
// e.g. BidiStream<EchoRequest, EchoResponse> bidiStream = echoClient.chatCallable().call();
TypeNode bidiStreamType =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this method is already named bidi, do the variable names still need bidi in them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used bidiStream to match the original sample code syntax, but I am open to the variable name. A stream variable in server is stream, so I think it make sense use stream instead of bidiStream. Are you also preferring using stream instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's for matching the variable name, then bidiStream LGTM.

TypeNode.withReference(
ConcreteReference.builder()
.setClazz(BidiStream.class)
.setGenerics(method.inputType().reference(), method.outputType().reference())
.build());
VariableExpr bidiStreamVarExpr =
VariableExpr.withVariable(
Variable.builder().setName("bidiStream").setType(bidiStreamType).build());
MethodInvocationExpr clientBidiStreamCallMethodInvoationExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(clientVarExpr)
.setMethodName(JavaStyle.toLowerCamelCase(String.format("%sCallable", method.name())))
.build();
clientBidiStreamCallMethodInvoationExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(clientBidiStreamCallMethodInvoationExpr)
.setMethodName("call")
.setReturnType(bidiStreamType)
.build();
AssignmentExpr bidiStreamAssignmentExpr =
AssignmentExpr.builder()
.setVariableExpr(bidiStreamVarExpr.toBuilder().setIsDecl(true).build())
.setValueExpr(clientBidiStreamCallMethodInvoationExpr)
.build();
bodyExprs.add(bidiStreamAssignmentExpr);

// Add request with default value expression.
bodyExprs.add(requestAssignmentExpr);

// Invoke send method with argument request.
// e.g. bidiStream.send(request);
MethodInvocationExpr sendMethodInvocationExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(bidiStreamVarExpr)
.setArguments(requestAssignmentExpr.variableExpr().toBuilder().setIsDecl(false).build())
.setMethodName("send")
.build();
bodyExprs.add(sendMethodInvocationExpr);

List<Statement> bodyStatements =
bodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList());

// For-loop on bidi stream variable.
// e.g. for (EchoResponse response : bidiStream) {
// // Do something when reveive a response.
// }
ForStatement forStatement =
ForStatement.builder()
.setLocalVariableExpr(
VariableExpr.builder()
.setVariable(
Variable.builder().setType(method.outputType()).setName("response").build())
.setIsDecl(true)
.build())
.setCollectionExpr(bidiStreamVarExpr)
.setBody(
Arrays.asList(
CommentStatement.withComment(
LineComment.withComment("Do something when a response is received."))))
.build();
bodyStatements.add(forStatement);

return bodyStatements;
}

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

// Create a list of RPC method arguments' variable expressions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,49 @@ public class EchoClient implements BackgroundResource {
}

// AUTO-GENERATED DOCUMENTATION AND METHOD.
/** Sample code: */
/**
* Sample code:
*
* <pre>{@code
* try (EchoClient echoClient = EchoClient.create()) {
* BidiStream<EchoRequest, EchoResponse> bidiStream = echoClient.chatCallable().call();
* EchoRequest request =
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setFoobar(Foobar.newBuilder().build())
* .build();
* bidiStream.send(request);
* for (EchoResponse response : bidiStream) {
* // Do something when a response is received.
* }
* }
* }</pre>
*/
public final BidiStreamingCallable<EchoRequest, EchoResponse> chatCallable() {
return stub.chatCallable();
}

// AUTO-GENERATED DOCUMENTATION AND METHOD.
/** Sample code: */
/**
* Sample code:
*
* <pre>{@code
* try (EchoClient echoClient = EchoClient.create()) {
* BidiStream<EchoRequest, EchoResponse> bidiStream = echoClient.chatAgainCallable().call();
* EchoRequest request =
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setFoobar(Foobar.newBuilder().build())
* .build();
* bidiStream.send(request);
* for (EchoResponse response : bidiStream) {
* // Do something when a response is received.
* }
* }
* }</pre>
*/
public final BidiStreamingCallable<EchoRequest, EchoResponse> chatAgainCallable() {
return stub.chatAgainCallable();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1767,5 +1767,93 @@ public void invalidComposeStreamCallableMethodHeaderSampleCode_serverStreamNotEx
ServiceClientSampleCodeComposer.composeStreamCallableMethodHeaderSampleCode(
method, clientType, resourceNames, messageTypes));
}

@Test
public void validComposeStreamCallableMethodHeaderSampleCode_bidiStream() {
FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor();
Map<String, ResourceName> resourceNames = Parser.parseResourceNames(echoFileDescriptor);
Map<String, Message> messageTypes = Parser.parseMessages(echoFileDescriptor);
TypeNode clientType =
TypeNode.withReference(
VaporReference.builder()
.setName("EchoClient")
.setPakkage(SHOWCASE_PACKAGE_NAME)
.build());
TypeNode inputType =
TypeNode.withReference(
VaporReference.builder()
.setName("EchoRequest")
.setPakkage(SHOWCASE_PACKAGE_NAME)
.build());
TypeNode outputType =
TypeNode.withReference(
VaporReference.builder()
.setName("EchoResponse")
.setPakkage(SHOWCASE_PACKAGE_NAME)
.build());
Method method =
Method.builder()
.setName("chat")
.setInputType(inputType)
.setOutputType(outputType)
.setStream(Stream.BIDI)
.build();
String results =
ServiceClientSampleCodeComposer.composeStreamCallableMethodHeaderSampleCode(
method, clientType, resourceNames, messageTypes);
String expected =
LineFormatter.lines(
"try (EchoClient echoClient = EchoClient.create()) {\n",
" BidiStream<EchoRequest, EchoResponse> bidiStream = echoClient.chatCallable().call();\n",
" EchoRequest request =\n",
" EchoRequest.newBuilder()\n",
" .setName(FoobarName.ofProjectFoobarName(\"[PROJECT]\", \"[FOOBAR]\").toString())\n",
" .setParent(FoobarName.ofProjectFoobarName(\"[PROJECT]\", \"[FOOBAR]\").toString())\n",
" .setFoobar(Foobar.newBuilder().build())\n",
" .build();\n",
" bidiStream.send(request);\n",
" for (EchoResponse response : bidiStream) {\n",
" // Do something when a response is received.\n",
" }\n",
"}");
assertEquals(results, expected);
}

@Test
public void invalidComposeStreamCallableMethodHeaderSampleCode_bidiStreamNotExistRequest() {
FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor();
Map<String, ResourceName> resourceNames = Parser.parseResourceNames(echoFileDescriptor);
Map<String, Message> messageTypes = Parser.parseMessages(echoFileDescriptor);
TypeNode clientType =
TypeNode.withReference(
VaporReference.builder()
.setName("EchoClient")
.setPakkage(SHOWCASE_PACKAGE_NAME)
.build());
TypeNode inputType =
TypeNode.withReference(
VaporReference.builder()
.setName("NotExistRequest")
.setPakkage(SHOWCASE_PACKAGE_NAME)
.build());
TypeNode outputType =
TypeNode.withReference(
VaporReference.builder()
.setName("EchoResponse")
.setPakkage(SHOWCASE_PACKAGE_NAME)
.build());
Method method =
Method.builder()
.setName("chat")
.setInputType(inputType)
.setOutputType(outputType)
.setStream(Stream.BIDI)
.build();
assertThrows(
NullPointerException.class,
() ->
ServiceClientSampleCodeComposer.composeStreamCallableMethodHeaderSampleCode(
method, clientType, resourceNames, messageTypes));
}
}