diff --git a/WORKSPACE b/WORKSPACE index 20673df00b..91c1361828 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -32,7 +32,8 @@ jvm_maven_import_external( # gapic-generator-java dependencies to match the order in googleapis repository, # which in its turn, prioritizes actual generated clients runtime dependencies # over the generator dependencies. -_gax_java_version = "2.3.0" + +_gax_java_version = "2.4.0" http_archive( name = "com_google_api_gax_java", diff --git a/repositories.bzl b/repositories.bzl index 67493dba45..d9010f6151 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -59,18 +59,18 @@ def gapic_generator_java_repositories(): _maybe( http_archive, name = "com_google_googleapis", - strip_prefix = "googleapis-efecdbf96311bb705d619459280ffc651b10844a", + strip_prefix = "googleapis-ba30d8097582039ac4cc4e21b4e4baa426423075", urls = [ - "https://github.com/googleapis/googleapis/archive/efecdbf96311bb705d619459280ffc651b10844a.zip", + "https://github.com/googleapis/googleapis/archive/ba30d8097582039ac4cc4e21b4e4baa426423075.zip", ], ) _maybe( http_archive, name = "com_google_googleapis_discovery", - strip_prefix = "googleapis-discovery-abf4cec1ce9e02e4d7d650bf66137c347cdd0d44", + strip_prefix = "googleapis-discovery-34478e2969042ed837d33684360f1ee3be7d2f74", urls = [ - "https://github.com/googleapis/googleapis-discovery/archive/abf4cec1ce9e02e4d7d650bf66137c347cdd0d44.zip", + "https://github.com/googleapis/googleapis-discovery/archive/34478e2969042ed837d33684360f1ee3be7d2f74.zip", ], ) diff --git a/src/main/java/com/google/api/generator/BUILD.bazel b/src/main/java/com/google/api/generator/BUILD.bazel index de7f95f193..4e678b5b7d 100644 --- a/src/main/java/com/google/api/generator/BUILD.bazel +++ b/src/main/java/com/google/api/generator/BUILD.bazel @@ -39,6 +39,7 @@ java_library( "//src/main/java/com/google/api/generator/gapic/model", "//src/main/java/com/google/api/generator/util", "@com_google_googleapis//google/api:api_java_proto", + "@com_google_googleapis//google/cloud:extended_operations_java_proto", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_guava_guava//jar", "@com_google_protobuf//:protobuf_java", diff --git a/src/main/java/com/google/api/generator/ProtoRegistry.java b/src/main/java/com/google/api/generator/ProtoRegistry.java index da4806bba0..d4cce56dcf 100644 --- a/src/main/java/com/google/api/generator/ProtoRegistry.java +++ b/src/main/java/com/google/api/generator/ProtoRegistry.java @@ -18,6 +18,7 @@ import com.google.api.ClientProto; import com.google.api.FieldBehaviorProto; import com.google.api.ResourceProto; +import com.google.cloud.ExtendedOperationsProto; import com.google.longrunning.OperationsProto; import com.google.protobuf.ExtensionRegistry; @@ -29,5 +30,6 @@ public static void registerAllExtensions(ExtensionRegistry extensionRegistry) { ClientProto.registerAllExtensions(extensionRegistry); ResourceProto.registerAllExtensions(extensionRegistry); FieldBehaviorProto.registerAllExtensions(extensionRegistry); + ExtendedOperationsProto.registerAllExtensions(extensionRegistry); } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java index 09aa5948a0..0c2fc84036 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java @@ -62,7 +62,8 @@ protected TransportContext getTransportContext() { @Override public GapicClass generate(GapicContext context, Service service) { - TypeStore typeStore = createTypes(); + TypeStore typeStore = createTypes(service); + String className = getTransportContext().classNames().getTransportServiceCallableFactoryClassName(service); GapicClass.Kind kind = Kind.STUB; @@ -77,9 +78,9 @@ public GapicClass generate(GapicContext context, Service service) { commentComposer.createTransportServiceCallableFactoryClassHeaderComments( service.name(), service.isDeprecated())) .setAnnotations(createClassAnnotations(service, typeStore)) - .setImplementsTypes(createClassImplements(typeStore)) + .setImplementsTypes(createClassImplements(service, typeStore)) .setName(className) - .setMethods(createClassMethods(typeStore)) + .setMethods(createClassMethods(service, typeStore)) .setScope(ScopeNode.PUBLIC) .build(); return GapicClass.create(kind, classDef); @@ -110,22 +111,23 @@ protected List createClassAnnotations(Service service, TypeStore * @return {@code TypeNode} containing the interface to be implemented by the generated callable * factory class. */ - protected abstract List createClassImplements(TypeStore typeStore); + protected abstract List createClassImplements(Service service, TypeStore typeStore); - protected List createClassMethods(TypeStore typeStore) { + protected List createClassMethods(Service service, TypeStore typeStore) { return Arrays.asList( - createUnaryCallableMethod(typeStore), - createPagedCallableMethod(typeStore), - createBatchingCallableMethod(typeStore), - createOperationCallableMethod(typeStore)); + createUnaryCallableMethod(service, typeStore), + createPagedCallableMethod(service, typeStore), + createBatchingCallableMethod(service, typeStore), + createOperationCallableMethod(service, typeStore)); } - protected MethodDefinition createUnaryCallableMethod(TypeStore typeStore) { + protected MethodDefinition createUnaryCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Unary"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -140,7 +142,7 @@ protected MethodDefinition createUnaryCallableMethod(TypeStore typeStore) { .collect(Collectors.toList())); } - protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { + protected MethodDefinition createPagedCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Paged"; String requestTemplateName = "RequestT"; String pagedResponseTemplateName = "PagedListResponseT"; @@ -148,6 +150,7 @@ protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName, pagedResponseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ "Unary", @@ -162,12 +165,13 @@ protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { .collect(Collectors.toList())); } - protected MethodDefinition createBatchingCallableMethod(TypeStore typeStore) { + protected MethodDefinition createBatchingCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Batching"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ "Unary", @@ -182,9 +186,11 @@ protected MethodDefinition createBatchingCallableMethod(TypeStore typeStore) { .collect(Collectors.toList())); } - protected abstract MethodDefinition createOperationCallableMethod(TypeStore typeStore); + protected abstract MethodDefinition createOperationCallableMethod( + Service service, TypeStore typeStore); protected MethodDefinition createGenericCallableMethod( + Service service, TypeStore typeStore, List methodTemplateNames, String returnCallableKindName, @@ -194,6 +200,7 @@ protected MethodDefinition createGenericCallableMethod( String callSettingsVariantName, List callSettingsTemplateObjects) { return createGenericCallableMethod( + service, typeStore, methodTemplateNames, returnCallableKindName, @@ -206,6 +213,7 @@ protected MethodDefinition createGenericCallableMethod( } protected MethodDefinition createGenericCallableMethod( + Service service, TypeStore typeStore, List methodTemplateNames, String returnCallableKindName, @@ -257,7 +265,7 @@ protected MethodDefinition createGenericCallableMethod( .setVariable( Variable.builder() .setName("operationsStub") - .setType(getTransportContext().operationsStubTypes().get(0)) + .setType(getOperationsStubType(service)) .build()) .setIsDecl(true) .build()); @@ -288,7 +296,16 @@ protected MethodDefinition createGenericCallableMethod( .build(); } - private static TypeStore createTypes() { + protected TypeNode getOperationsStubType(Service service) { + TypeNode operationsStubType = service.operationServiceStubType(); + if (operationsStubType == null) { + operationsStubType = getTransportContext().operationsStubTypes().get(0); + } + return operationsStubType; + } + + + private TypeStore createTypes(Service service) { List> concreteClazzes = Arrays.asList( // Gax-java classes. diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java index 528d24d202..beb777f543 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java @@ -132,7 +132,7 @@ public GapicClass generate(GapicContext context, Service service) { String className = ClassNames.getServiceClientClassName(service); GapicClass.Kind kind = Kind.MAIN; String pakkage = service.pakkage(); - boolean hasLroClient = service.hasLroMethods(); + boolean hasLroClient = service.hasStandardLroMethods(); Map> grpcRpcsToJavaMethodNames = new HashMap<>(); @@ -741,6 +741,7 @@ private static MethodDefinition createMethodDefaultMethod( method.isPaged() ? typeStore.get(String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, method.name())) : method.outputType(); + List annotations = new ArrayList<>(); if (method.hasLro()) { LongrunningOperation lro = method.lro(); methodOutputType = @@ -751,6 +752,13 @@ private static MethodDefinition createMethodDefaultMethod( .copyAndSetGenerics( Arrays.asList( lro.responseType().reference(), lro.metadataType().reference()))); + if (method.lro().operationServiceStubType() != null) { + annotations.add( + AnnotationNode.withTypeAndDescription( + typeStore.get("BetaApi"), + "The surface for long-running operations is not stable yet and may change in the" + + " future.")); + } } // Construct the method that accepts a request proto. @@ -792,8 +800,7 @@ private static MethodDefinition createMethodDefaultMethod( .setArguments(Arrays.asList(requestArgVarExpr)); if (method.isDeprecated()) { - methodBuilder = - methodBuilder.setAnnotations(Arrays.asList(AnnotationNode.withType(TypeNode.DEPRECATED))); + annotations.add(AnnotationNode.withType(TypeNode.DEPRECATED)); } if (isProtoEmptyType(methodOutputType)) { @@ -805,6 +812,9 @@ private static MethodDefinition createMethodDefaultMethod( methodBuilder = methodBuilder.setReturnExpr(callableMethodExpr).setReturnType(methodOutputType); } + + methodBuilder.setAnnotations(annotations); + return methodBuilder.build(); } diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java index 1c49899d15..b38ca70edd 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java @@ -20,8 +20,12 @@ import com.google.api.gax.rpc.BidiStreamingCallable; import com.google.api.gax.rpc.ClientStreamingCallable; import com.google.api.gax.rpc.InvalidArgumentException; +import com.google.api.gax.rpc.PagedCallSettings; +import com.google.api.gax.rpc.ServerStreamingCallSettings; import com.google.api.gax.rpc.ServerStreamingCallable; import com.google.api.gax.rpc.StatusCode; +import com.google.api.gax.rpc.StreamingCallSettings; +import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.generator.engine.ast.AnnotationNode; import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.ClassDefinition; @@ -54,6 +58,7 @@ import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.MethodArgument; +import com.google.api.generator.gapic.model.OperationResponse; import com.google.api.generator.gapic.model.ResourceName; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; @@ -408,7 +413,10 @@ private MethodDefinition createRpcTestMethod( .setValueExpr(expectedResponseValExpr) .build()); - if (method.hasLro()) { + if (method.hasLro() + && (method.lro().operationServiceStubType() == null + || !method.lro().responseType().equals(method.outputType()))) { + VariableExpr resultOperationVarExpr = VariableExpr.withVariable( Variable.builder() @@ -905,6 +913,46 @@ private void addDynamicTypes(GapicContext context, Service service, TypeStore ty } } + private static TypeNode getCallSettingsTypeHelper( + Method protoMethod, TypeStore typeStore, boolean isBuilder) { + Class callSettingsClazz = isBuilder ? UnaryCallSettings.Builder.class : UnaryCallSettings.class; + if (protoMethod.isPaged()) { + callSettingsClazz = isBuilder ? PagedCallSettings.Builder.class : PagedCallSettings.class; + } else { + switch (protoMethod.stream()) { + case CLIENT: + // Fall through. + case BIDI: + callSettingsClazz = + isBuilder ? StreamingCallSettings.Builder.class : StreamingCallSettings.class; + break; + case SERVER: + callSettingsClazz = + isBuilder + ? ServerStreamingCallSettings.Builder.class + : ServerStreamingCallSettings.class; + break; + case NONE: + // Fall through + default: + // Fall through + } + } + + List generics = new ArrayList<>(); + generics.add(protoMethod.inputType().reference()); + generics.add(protoMethod.outputType().reference()); + if (protoMethod.isPaged()) { + generics.add( + typeStore + .get(String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, protoMethod.name())) + .reference()); + } + + return TypeNode.withReference( + ConcreteReference.builder().setClazz(callSettingsClazz).setGenerics(generics).build()); + } + protected static TypeNode getCallableType(Method protoMethod) { Preconditions.checkState( !protoMethod.stream().equals(Method.Stream.NONE), diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java index 3f80382bab..b50f15ff38 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java @@ -18,17 +18,22 @@ import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.rpc.BidiStreamingCallable; import com.google.api.gax.rpc.ClientStreamingCallable; +import com.google.api.gax.rpc.LongRunningClient; import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.ServerStreamingCallable; import com.google.api.gax.rpc.UnaryCallable; import com.google.api.generator.engine.ast.AnnotationNode; import com.google.api.generator.engine.ast.ClassDefinition; +import com.google.api.generator.engine.ast.ConcreteReference; import com.google.api.generator.engine.ast.ExprStatement; import com.google.api.generator.engine.ast.MethodDefinition; import com.google.api.generator.engine.ast.Reference; import com.google.api.generator.engine.ast.ScopeNode; +import com.google.api.generator.engine.ast.Statement; import com.google.api.generator.engine.ast.ThrowExpr; import com.google.api.generator.engine.ast.TypeNode; +import com.google.api.generator.engine.ast.Variable; +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; @@ -40,6 +45,7 @@ import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; +import com.google.common.collect.ImmutableList; import com.google.longrunning.Operation; import java.util.ArrayList; import java.util.Arrays; @@ -51,6 +57,7 @@ import javax.annotation.Generated; public abstract class AbstractServiceStubClassComposer implements ClassComposer { + private static final String DOT = "."; private static final String PAGED_RESPONSE_TYPE_NAME_PATTERN = "%sPagedResponse"; private final TransportContext transportContext; @@ -111,11 +118,15 @@ private static List createClassImplements(TypeStore typeStore) { private List createClassMethods( Service service, Map messageTypes, TypeStore typeStore) { - boolean hasLroClient = service.hasLroMethods(); List methods = new ArrayList<>(); - if (hasLroClient) { - methods.addAll(createOperationsStubGetters(typeStore)); + if (service.hasStandardLroMethods()) { + TypeNode operationsStubType = service.operationServiceStubType(); + methods.addAll(createOperationsStubGetters(typeStore, operationsStubType)); } + + if (service.operationPollingMethod() != null) { + methods.addAll(createLongRunningClientGetters(typeStore)); + } methods.addAll(createCallableGetters(service, messageTypes, typeStore)); methods.addAll(createBackgroundResourceMethodOverrides()); return methods; @@ -138,7 +149,8 @@ private List createCallableGetters( return javaMethods; } - private MethodDefinition createOperationCallableGetter(Method method, TypeStore typeStore) { + private MethodDefinition createOperationCallableGetter( + Method method, TypeStore typeStore) { return createCallableGetterHelper(method, typeStore, true, false); } @@ -198,7 +210,7 @@ private MethodDefinition createCallableGetterHelper( return createCallableGetterMethodDefinition(returnType, methodName, annotations, typeStore); } - private List createOperationsStubGetters(TypeStore typeStore) { + private List createOperationsStubGetters(TypeStore typeStore, TypeNode operationsStubType) { List getters = new ArrayList<>(); Iterator operationStubNameIt = @@ -208,15 +220,26 @@ private List createOperationsStubGetters(TypeStore typeStore) while (operationStubNameIt.hasNext() && operationStubTypeIt.hasNext()) { String methodName = String.format("get%s", JavaStyle.toUpperCamelCase(operationStubNameIt.next())); + //TODO: refactor this + TypeNode actualOperationsStubType = operationStubTypeIt.next(); + if (operationsStubType != null) { + actualOperationsStubType = operationsStubType; + } - getters.add( - createOperationsStubGetterMethodDefinition( - operationStubTypeIt.next(), methodName, typeStore)); + getters.add(createOperationsStubGetterMethodDefinition(actualOperationsStubType, methodName, typeStore)); } return getters; } + private List createLongRunningClientGetters(TypeStore typeStore) { + return ImmutableList.of(createCallableGetterMethodDefinition( + TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class)), + "longRunningClient", + ImmutableList.of(AnnotationNode.withType(typeStore.get("BetaApi"))), + typeStore)); + } + private static List createBackgroundResourceMethodOverrides() { MethodDefinition closeMethod = MethodDefinition.builder() @@ -260,10 +283,7 @@ private static TypeStore createTypes(Service service, Map messa } protected MethodDefinition createCallableGetterMethodDefinition( - TypeNode returnType, - String methodName, - List annotations, - TypeStore typeStore) { + TypeNode returnType, String methodName, List annotations, TypeStore typeStore) { return MethodDefinition.builder() .setScope(ScopeNode.PUBLIC) .setAnnotations(annotations) @@ -294,4 +314,8 @@ protected MethodDefinition createOperationsStubGetterMethodDefinition( .build()))) .build(); } + + private static String getClientClassName(Service service) { + return String.format("%sClient", service.overriddenName()); + } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java index 7137f4f1fb..0d190273a3 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java @@ -17,9 +17,11 @@ import com.google.api.core.BetaApi; import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.core.BackgroundResourceAggregation; +import com.google.api.gax.longrunning.OperationSnapshot; import com.google.api.gax.rpc.BidiStreamingCallable; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.ClientStreamingCallable; +import com.google.api.gax.rpc.LongRunningClient; import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.RequestParamsExtractor; import com.google.api.gax.rpc.ServerStreamingCallable; @@ -44,19 +46,21 @@ import com.google.api.generator.engine.ast.TryCatchStatement; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; +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.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; import com.google.api.generator.gapic.model.GapicContext; +import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; 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.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.longrunning.Operation; import java.io.IOException; @@ -72,6 +76,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import javax.annotation.Generated; +import javax.annotation.Nullable; public abstract class AbstractTransportServiceStubClassComposer implements ClassComposer { private static final Statement EMPTY_LINE_STATEMENT = EmptyLineStatement.create(); @@ -116,6 +121,7 @@ private static TypeStore createStaticTypes() { IOException.class, Operation.class, OperationCallable.class, + OperationSnapshot.class, RequestParamsExtractor.class, ServerStreamingCallable.class, TimeUnit.class, @@ -147,14 +153,24 @@ public GapicClass generate(GapicContext context, Service service) { .build())); if (generateOperationsStubLogic(service)) { // Transport-specific service stub may have only one element of the following, thus get(0). + TypeNode operationsStubType = getTransportOperationsStubType(service); classMemberVarExprs.put( getTransportContext().transportOperationsStubNames().get(0), VariableExpr.withVariable( Variable.builder() .setName(getTransportContext().transportOperationsStubNames().get(0)) - .setType(getTransportContext().transportOperationsStubTypes().get(0)) + .setType(operationsStubType) .build())); } + + boolean operationPollingMethod = checkOperationPollingMethod(service); + if (operationPollingMethod) { + VariableExpr longRunningVarExpr = declareLongRunningClient(); + if (longRunningVarExpr != null) { + classMemberVarExprs.put("longRunningClient", longRunningVarExpr); + } + } + classMemberVarExprs.put( CALLABLE_FACTORY_MEMBER_NAME, VariableExpr.withVariable( @@ -163,12 +179,14 @@ public GapicClass generate(GapicContext context, Service service) { .setType(getTransportContext().stubCallableFactoryType()) .build())); + Map messageTypes = context.messages(); List classStatements = createClassStatements( service, protoMethodNameToDescriptorVarExprs, callableClassMemberVarExprs, - classMemberVarExprs); + classMemberVarExprs, + messageTypes); StubCommentComposer commentComposer = new StubCommentComposer(getTransportContext().transportName()); @@ -182,7 +200,8 @@ public GapicClass generate(GapicContext context, Service service) { .setAnnotations(createClassAnnotations(service)) .setScope(ScopeNode.PUBLIC) .setName(className) - .setExtendsType(typeStore.get(ClassNames.getServiceStubClassName(service))) + .setExtendsType( + typeStore.get(getTransportContext().classNames().getServiceStubClassName(service))) .setStatements(classStatements) .setMethods( createClassMethods( @@ -196,7 +215,10 @@ public GapicClass generate(GapicContext context, Service service) { } protected abstract Statement createMethodDescriptorVariableDecl( - Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr); + Service service, + Method protoMethod, + VariableExpr methodDescriptorVarExpr, + Map messageTypes); protected boolean generateOperationsStubLogic(Service service) { return true; @@ -233,14 +255,26 @@ protected List createGetMethodDescriptorsMethod( return Arrays.asList(); } + protected List createTypeRegistry(Service service) { + return Arrays.asList(); + } + protected List createClassStatements( Service service, Map protoMethodNameToDescriptorVarExprs, Map callableClassMemberVarExprs, - Map classMemberVarExprs) { + Map classMemberVarExprs, + Map messageTypes) { List classStatements = new ArrayList<>(); + + classStatements.addAll(createTypeRegistry(service)); + if (!classStatements.isEmpty()) { + classStatements.add(EMPTY_LINE_STATEMENT); + } + for (Statement statement : - createMethodDescriptorVariableDecls(service, protoMethodNameToDescriptorVarExprs)) { + createMethodDescriptorVariableDecls( + service, protoMethodNameToDescriptorVarExprs, messageTypes)) { classStatements.add(statement); classStatements.add(EMPTY_LINE_STATEMENT); } @@ -249,16 +283,20 @@ protected List createClassStatements( classStatements.add(EMPTY_LINE_STATEMENT); classStatements.addAll(createClassMemberFieldDeclarations(classMemberVarExprs)); + classStatements.add(EMPTY_LINE_STATEMENT); + return classStatements; } protected List createMethodDescriptorVariableDecls( - Service service, Map protoMethodNameToDescriptorVarExprs) { + Service service, + Map protoMethodNameToDescriptorVarExprs, + Map messageTypes) { return service.methods().stream() .map( m -> createMethodDescriptorVariableDecl( - service, m, protoMethodNameToDescriptorVarExprs.get(m.name()))) + service, m, protoMethodNameToDescriptorVarExprs.get(m.name()), messageTypes)) .collect(Collectors.toList()); } @@ -406,7 +444,8 @@ protected List createClassMethods( classMemberVarExprs.get(getTransportContext().transportOperationsStubNames().get(0)))); javaMethods.addAll(createCallableGetterMethods(callableClassMemberVarExprs)); javaMethods.addAll( - createStubOverrideMethods(classMemberVarExprs.get(BACKGROUND_RESOURCES_MEMBER_NAME))); + createStubOverrideMethods( + classMemberVarExprs.get(BACKGROUND_RESOURCES_MEMBER_NAME), service)); return javaMethods; } @@ -434,7 +473,8 @@ protected List createStaticCreatorMethods( argList -> NewObjectExpr.builder().setType(creatorMethodReturnType).setArguments(argList).build(); - TypeNode stubSettingsType = typeStore.get(ClassNames.getServiceStubSettingsClassName(service)); + TypeNode stubSettingsType = + typeStore.get(getTransportContext().classNames().getServiceStubSettingsClassName(service)); VariableExpr settingsVarExpr = VariableExpr.withVariable( Variable.builder().setName("settings").setType(stubSettingsType).build()); @@ -496,7 +536,8 @@ protected List createConstructorMethods( Map classMemberVarExprs, Map callableClassMemberVarExprs, Map protoMethodNameToDescriptorVarExprs) { - TypeNode stubSettingsType = typeStore.get(ClassNames.getServiceStubSettingsClassName(service)); + TypeNode stubSettingsType = + typeStore.get(getTransportContext().classNames().getServiceStubSettingsClassName(service)); VariableExpr settingsVarExpr = VariableExpr.withVariable( Variable.builder().setName("settings").setType(stubSettingsType).build()); @@ -570,20 +611,14 @@ protected List createConstructorMethods( .build()); VariableExpr operationsStubClassVarExpr = classMemberVarExprs.get(getTransportContext().transportOperationsStubNames().get(0)); + // TODO: refactor this if (generateOperationsStubLogic(service)) { - secondCtorExprs.add( - AssignmentExpr.builder() - .setVariableExpr( - operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) - .setValueExpr( - MethodInvocationExpr.builder() - .setStaticReferenceType( - getTransportContext().transportOperationsStubTypes().get(0)) - .setMethodName("create") - .setArguments(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr)) - .setReturnType(operationsStubClassVarExpr.type()) - .build()) - .build()); + secondCtorExprs.addAll(createOperationsStubInitExpr( + service, + thisExpr, + operationsStubClassVarExpr, + clientContextVarExpr, + callableFactoryVarExpr)); } secondCtorStatements.addAll( secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList())); @@ -649,12 +684,15 @@ protected List createConstructorMethods( secondCtorExprs.clear(); secondCtorStatements.add(EMPTY_LINE_STATEMENT); + secondCtorStatements.addAll(createLongRunningClient(service, typeStore)); + // Instantiate backgroundResources. MethodInvocationExpr getBackgroundResourcesMethodExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(clientContextVarExpr) .setMethodName("getBackgroundResources") .build(); + VariableExpr backgroundResourcesVarExpr = classMemberVarExprs.get("backgroundResources"); secondCtorExprs.add( AssignmentExpr.builder() @@ -679,6 +717,36 @@ protected List createConstructorMethods( return Arrays.asList(firstCtor, secondCtor); } + protected List createOperationsStubInitExpr( + Service service, + Expr thisExpr, + VariableExpr operationsStubClassVarExpr, + VariableExpr clientContextVarExpr, + VariableExpr callableFactoryVarExpr) { + TypeNode opeationsStubType = getTransportOperationsStubType(service); + return Collections.singletonList( + AssignmentExpr.builder() + .setVariableExpr( + operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) + .setValueExpr( + MethodInvocationExpr.builder() + .setStaticReferenceType(opeationsStubType) + .setMethodName("create") + .setArguments(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr)) + .setReturnType(operationsStubClassVarExpr.type()) + .build()) + .build()); + } + + protected List createLongRunningClient(Service service, TypeStore typeStore) { + return ImmutableList.of(); + } + + @Nullable + protected VariableExpr declareLongRunningClient() { + return null; + } + private Expr createCallableInitExpr( String callableVarName, VariableExpr callableVarExpr, @@ -795,7 +863,7 @@ private static List createCallableGetterMethods( } private List createStubOverrideMethods( - VariableExpr backgroundResourcesVarExpr) { + VariableExpr backgroundResourcesVarExpr, Service service) { Function methodMakerStarterFn = methodName -> MethodDefinition.builder() @@ -859,6 +927,9 @@ private List createStubOverrideMethods( .build()) .build(); List javaMethods = new ArrayList<>(); + if (service.operationPollingMethod() != null) { + javaMethods.addAll(createLongRunningClientGetters()); + } javaMethods.add( methodMakerStarterFn .apply("close") @@ -931,14 +1002,38 @@ private List createStubOverrideMethods( return javaMethods; } + private boolean checkOperationPollingMethod(Service service) { + return service.methods().stream().anyMatch(Method::isOperationPollingMethod); + } + + protected List createLongRunningClientGetters() { + VariableExpr longRunningClient = + VariableExpr.withVariable( + Variable.builder() + .setName("longRunningClient") + .setType( + TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class))) + .build()); + + return ImmutableList.of( + MethodDefinition.builder() + .setName("longRunningClient") + .setScope(ScopeNode.PUBLIC) + .setIsOverride(true) + .setReturnType( + TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class))) + .setReturnExpr(longRunningClient) + .build()); + } + private TypeStore createDynamicTypes(Service service, String stubPakkage) { TypeStore typeStore = new TypeStore(); typeStore.putAll( stubPakkage, Arrays.asList( getTransportContext().classNames().getTransportServiceStubClassName(service), - ClassNames.getServiceStubSettingsClassName(service), - ClassNames.getServiceStubClassName(service), + getTransportContext().classNames().getServiceStubSettingsClassName(service), + getTransportContext().classNames().getServiceStubClassName(service), getTransportContext() .classNames() .getTransportServiceCallableFactoryClassName(service))); @@ -950,7 +1045,7 @@ private TypeStore createDynamicTypes(Service service, String stubPakkage) { .map(m -> String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, m.name())) .collect(Collectors.toList()), true, - ClassNames.getServiceClientClassName(service)); + getTransportContext().classNames().getServiceClientClassName(service)); return typeStore; } @@ -998,4 +1093,20 @@ protected String getProtoRpcFullMethodName(Service protoService, Method protoMet return String.format( "%s.%s/%s", protoService.protoPakkage(), protoService.name(), protoMethod.name()); } + + protected TypeNode getTransportOperationsStubType(Service service) { + TypeNode transportOpeationsStubType = service.operationServiceStubType(); + if (transportOpeationsStubType == null) { + transportOpeationsStubType = getTransportContext().transportOperationsStubTypes().get(0); + } else { + transportOpeationsStubType = + TypeNode.withReference( + VaporReference.builder() + .setName("HttpJson" + transportOpeationsStubType.reference().simpleName()) + .setPakkage(transportOpeationsStubType.reference().pakkage()) + .build()); + } + + return transportOpeationsStubType; + } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java index f697c1b4a2..8862984755 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java @@ -27,6 +27,7 @@ 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.VaporReference; import com.google.api.generator.engine.ast.Variable; import com.google.api.generator.engine.ast.VariableExpr; import com.google.api.generator.gapic.composer.resourcename.ResourceNameTokenizer; @@ -262,9 +263,12 @@ public static Expr createSimpleMessageBuilderExpr( .setStaticReferenceType(message.type()) .setMethodName("newBuilder") .build(); + for (Field field : message.fields()) { if (field.isContainedInOneof() // Avoid colliding fields. - || ((field.isMessage() || field.isEnum()) // Avoid importing unparsed messages. + || ((field.isMessage() + || (field.isEnum() + && message.operationResponse() == null)) // Avoid importing unparsed messages. && !field.isRepeated() && !messageTypes.containsKey(field.type().reference().fullName()))) { continue; @@ -289,7 +293,34 @@ public static Expr createSimpleMessageBuilderExpr( .setReturnType(TypeNode.STRING) .build(); } else { - defaultExpr = createDefaultValue(field, true); + if (message.operationResponse() != null) { + if (field.name().equals(message.operationResponse().statusFieldName())) { + String statusTypeName = message.operationResponse().statusFieldTypeName(); + String statusClassName = statusTypeName.substring(statusTypeName.lastIndexOf('.') + 1); + + TypeNode statusType = + TypeNode.withReference( + VaporReference.builder() + .setName(statusClassName) + .setPakkage(message.type().reference().fullName()) + .setIsStaticImport(false) + .build()); + defaultExpr = + VariableExpr.builder() + .setVariable(Variable.builder().setName("DONE").setType(statusType).build()) + .setStaticReferenceType(statusType) + .build(); + + } else if (field.name().equals(message.operationResponse().errorCodeFieldName())) { + defaultExpr = + ValueExpr.withValue( + PrimitiveValue.builder().setType(field.type()).setValue("0").build()); + } + } + + if (defaultExpr == null) { + defaultExpr = createDefaultValue(field, true); + } } builderExpr = MethodInvocationExpr.builder() diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java index e953c1410a..581066f3e6 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java @@ -19,6 +19,7 @@ import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.gapic.composer.common.AbstractServiceCallableFactoryClassComposer; import com.google.api.generator.gapic.composer.store.TypeStore; +import com.google.api.generator.gapic.model.Service; import com.google.longrunning.Operation; import java.util.ArrayList; import java.util.Arrays; @@ -41,28 +42,30 @@ public static GrpcServiceCallableFactoryClassComposer instance() { } @Override - protected List createClassImplements(TypeStore typeStore) { + protected List createClassImplements(Service service, TypeStore typeStore) { return Arrays.asList(getTransportContext().stubCallableFactoryType()); } @Override - protected List createClassMethods(TypeStore typeStore) { - List classMethods = new ArrayList<>(super.createClassMethods(typeStore)); + protected List createClassMethods(Service service, TypeStore typeStore) { + List classMethods = + new ArrayList<>(super.createClassMethods(service, typeStore)); classMethods.addAll( Arrays.asList( - createBidiStreamingCallableMethod(typeStore), - createServerStreamingCallableMethod(typeStore), - createClientStreamingCallableMethod(typeStore))); + createBidiStreamingCallableMethod(service, typeStore), + createServerStreamingCallableMethod(service, typeStore), + createClientStreamingCallableMethod(service, typeStore))); return classMethods; } @Override - protected MethodDefinition createUnaryCallableMethod(TypeStore typeStore) { + protected MethodDefinition createUnaryCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Unary"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -78,7 +81,7 @@ protected MethodDefinition createUnaryCallableMethod(TypeStore typeStore) { } @Override - protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { + protected MethodDefinition createPagedCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Paged"; String requestTemplateName = "RequestT"; String pagedResponseTemplateName = "PagedListResponseT"; @@ -86,6 +89,7 @@ protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName, pagedResponseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ "Unary", @@ -101,13 +105,14 @@ protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { } @Override - protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { + protected MethodDefinition createOperationCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Operation"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName, "MetadataT"); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -120,12 +125,13 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { .collect(Collectors.toList())); } - private MethodDefinition createBidiStreamingCallableMethod(TypeStore typeStore) { + private MethodDefinition createBidiStreamingCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "BidiStreaming"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -140,12 +146,14 @@ private MethodDefinition createBidiStreamingCallableMethod(TypeStore typeStore) .collect(Collectors.toList())); } - private MethodDefinition createServerStreamingCallableMethod(TypeStore typeStore) { + private MethodDefinition createServerStreamingCallableMethod( + Service service, TypeStore typeStore) { String methodVariantName = "ServerStreaming"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -160,12 +168,14 @@ private MethodDefinition createServerStreamingCallableMethod(TypeStore typeStore .collect(Collectors.toList())); } - private MethodDefinition createClientStreamingCallableMethod(TypeStore typeStore) { + private MethodDefinition createClientStreamingCallableMethod( + Service service, TypeStore typeStore) { String methodVariantName = "ClientStreaming"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java index 578ce02005..c82de5552c 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java @@ -33,6 +33,7 @@ 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.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.Service; import com.google.api.generator.gapic.utils.JavaStyle; @@ -84,7 +85,10 @@ private static TypeStore createStaticTypes() { @Override protected Statement createMethodDescriptorVariableDecl( - Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr) { + Service service, + Method protoMethod, + VariableExpr methodDescriptorVarExpr, + Map messageTypes) { MethodInvocationExpr methodDescriptorMaker = MethodInvocationExpr.builder() .setMethodName("newBuilder") diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java index 3f84bf3c97..59376001e2 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java @@ -14,7 +14,6 @@ package com.google.api.generator.gapic.composer.grpcrest; -import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.grpc.GrpcTransportChannel; import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider; import com.google.api.gax.grpc.ProtoOperationTransformers; @@ -72,7 +71,8 @@ public abstract class GrpcRestContext extends TransportContext { .setTransportCallableFactoryType(null) .setOperationsStubTypes( ImmutableList.of( - classToType(OperationsStub.class), classToType(BackgroundResource.class))) + classToType(OperationsStub.class), + classToType(com.google.api.gax.httpjson.longrunning.stub.OperationsStub.class))) .setTransportCallSettingsName(null) // For RetrySettingsComposer // TODO: fix when LRO for REST RE FIXED diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java index 1ed6296cfa..88ccc1e0c9 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java @@ -14,15 +14,27 @@ package com.google.api.generator.gapic.composer.rest; -import com.google.api.gax.httpjson.ApiMessage; +import com.google.api.gax.httpjson.HttpJsonCallableFactory; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; +import com.google.api.gax.rpc.OperationCallable; +import com.google.api.gax.rpc.UnaryCallable; import com.google.api.generator.engine.ast.AnnotationNode; +import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.ConcreteReference; +import com.google.api.generator.engine.ast.ExprStatement; import com.google.api.generator.engine.ast.MethodDefinition; +import com.google.api.generator.engine.ast.MethodInvocationExpr; +import com.google.api.generator.engine.ast.NewObjectExpr; +import com.google.api.generator.engine.ast.Statement; import com.google.api.generator.engine.ast.TypeNode; -import com.google.api.generator.engine.ast.ValueExpr; +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.common.AbstractServiceCallableFactoryClassComposer; import com.google.api.generator.gapic.composer.store.TypeStore; import com.google.api.generator.gapic.model.Service; +import com.google.longrunning.Operation; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -32,8 +44,8 @@ public class HttpJsonServiceCallableFactoryClassComposer private static final HttpJsonServiceCallableFactoryClassComposer INSTANCE = new HttpJsonServiceCallableFactoryClassComposer(); - private static final TypeNode MESSAGE_TYPE = - TypeNode.withReference(ConcreteReference.withClazz(ApiMessage.class)); + private static final TypeNode DEFAULT_OPERATION_TYPE = + TypeNode.withReference(ConcreteReference.withClazz(Operation.class)); private HttpJsonServiceCallableFactoryClassComposer() { super(RestContext.instance()); @@ -58,23 +70,29 @@ protected List createClassAnnotations(Service service, TypeStore } @Override - protected List createClassImplements(TypeStore typeStore) { + protected List createClassImplements(Service service, TypeStore typeStore) { + TypeNode operationsStubType = getOperationsStubType(service); + + TypeNode operationType = service.operationType(); + if (operationType == null) { + operationType = DEFAULT_OPERATION_TYPE; + } + return Arrays.asList( TypeNode.withReference( getTransportContext() .stubCallableFactoryType() .reference() .copyAndSetGenerics( - Arrays.asList( - MESSAGE_TYPE.reference(), - getTransportContext().operationsStubTypes().get(0).reference())))); + Arrays.asList(operationType.reference(), operationsStubType.reference())))); } @Override - protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { + protected MethodDefinition createOperationCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Operation"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; + List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName, "MetadataT"); @@ -88,20 +106,143 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { "The surface for long-running operations is not stable yet and may change in the" + " future."); + // Generate generic method without the body + TypeNode operationType = service.operationType(); + if (operationType == null) { + operationType = DEFAULT_OPERATION_TYPE; + } MethodDefinition method = createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, /*returnCallableTemplateNames=*/ methodTemplateNames, /*methodVariantName=*/ methodVariantName, /*httpJsonCallSettingsTemplateObjects=*/ Arrays.asList( - requestTemplateName, MESSAGE_TYPE), + requestTemplateName, operationType), /*callSettingsVariantName=*/ methodVariantName, /*callSettingsTemplateObjects=*/ methodTemplateNames.stream() .map(n -> (Object) n) .collect(Collectors.toList()), Arrays.asList(betaAnnotation)); - return method.toBuilder().setReturnExpr(ValueExpr.createNullExpr()).build(); + + List createOperationCallableBody = new ArrayList<>(); + List arguments = new ArrayList<>(method.arguments()); + + Variable httpJsonCallSettingsVar = arguments.get(0).variable(); + Variable operationCallSettingsVar = arguments.get(1).variable(); + Variable clientContextVar = arguments.get(2).variable(); + Variable operationsStubVar = arguments.get(3).variable(); + // Generate innerCallable + VariableExpr innerCallableVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setName("innerCallable") + .setType( + TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) + .build()) + .setTemplateObjects(Arrays.asList(requestTemplateName, methodVariantName)) + .build(); + MethodInvocationExpr getInitialCallSettingsExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(VariableExpr.withVariable(operationCallSettingsVar)) + .setMethodName("getInitialCallSettings") + .build(); + MethodInvocationExpr createBaseUnaryCallableExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType( + TypeNode.withReference(ConcreteReference.withClazz(HttpJsonCallableFactory.class))) + .setMethodName("createBaseUnaryCallable") + .setArguments( + VariableExpr.withVariable(httpJsonCallSettingsVar), + getInitialCallSettingsExpr, + VariableExpr.withVariable(clientContextVar)) + .setReturnType(TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) + .build(); + AssignmentExpr innerCallableAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(innerCallableVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(createBaseUnaryCallableExpr) + .build(); + createOperationCallableBody.add(ExprStatement.withExpr(innerCallableAssignExpr)); + + // This is a temporary solution + VaporReference requestT = + VaporReference.builder() + .setName("RequestT") + .setPakkage(service.pakkage() + ".stub") + .build(); + + TypeNode initialCallableType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(HttpJsonOperationSnapshotCallable.class) + .setGenerics(requestT, operationType.reference()) + .build()); + + // Generate initialCallable + VariableExpr initialCallableVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder().setName("initialCallable").setType(initialCallableType).build()) + .build(); + MethodInvocationExpr getMethodDescriptorExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(VariableExpr.withVariable(httpJsonCallSettingsVar)) + .setMethodName("getMethodDescriptor") + .build(); + MethodInvocationExpr getOperationSnapshotFactoryExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(getMethodDescriptorExpr) + .setMethodName("getOperationSnapshotFactory") + .build(); + + TypeNode operationSnapshotCallableType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(HttpJsonOperationSnapshotCallable.class) + .setGenerics(requestT, operationType.reference()) + .build()); + NewObjectExpr initialCallableObject = + NewObjectExpr.builder() + .setType(operationSnapshotCallableType) + .setIsGeneric(true) + .setArguments(innerCallableVarExpr, getOperationSnapshotFactoryExpr) + .build(); + AssignmentExpr initialCallableAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(initialCallableVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(initialCallableObject) + .build(); + createOperationCallableBody.add(ExprStatement.withExpr(initialCallableAssignExpr)); + + // Generate return statement + MethodInvocationExpr longRunningClient = + MethodInvocationExpr.builder() + .setExprReferenceExpr(VariableExpr.withVariable(operationsStubVar)) + .setMethodName("longRunningClient") + .build(); + MethodInvocationExpr createOperationCallable = + MethodInvocationExpr.builder() + .setStaticReferenceType( + TypeNode.withReference(ConcreteReference.withClazz(HttpJsonCallableFactory.class))) + .setMethodName("createOperationCallable") + .setArguments( + VariableExpr.withVariable(operationCallSettingsVar), + VariableExpr.withVariable(clientContextVar), + longRunningClient, + initialCallableVarExpr) + .setReturnType( + TypeNode.withReference(ConcreteReference.withClazz(OperationCallable.class))) + .build(); + + // Add body and return statement to method + return method + .toBuilder() + .setBody(createOperationCallableBody) + .setReturnExpr(createOperationCallable) + .build(); } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java index 50ea1ad57e..f3770e5ca9 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java @@ -19,10 +19,16 @@ import com.google.api.gax.httpjson.ApiMethodDescriptor; import com.google.api.gax.httpjson.FieldsExtractor; import com.google.api.gax.httpjson.HttpJsonCallSettings; +import com.google.api.gax.httpjson.HttpJsonLongRunningClient; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshot; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.httpjson.ProtoMessageRequestFormatter; import com.google.api.gax.httpjson.ProtoMessageResponseParser; import com.google.api.gax.httpjson.ProtoRestSerializer; +import com.google.api.gax.httpjson.longrunning.stub.HttpJsonOperationsStub; +import com.google.api.gax.longrunning.OperationSnapshot; +import com.google.api.gax.rpc.LongRunningClient; +import com.google.api.gax.rpc.UnaryCallable; import com.google.api.generator.engine.ast.AnnotationNode; import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.ConcreteReference; @@ -34,20 +40,27 @@ import com.google.api.generator.engine.ast.MethodDefinition; import com.google.api.generator.engine.ast.MethodInvocationExpr; import com.google.api.generator.engine.ast.NewObjectExpr; +import com.google.api.generator.engine.ast.PrimitiveValue; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; import com.google.api.generator.engine.ast.StringObjectValue; +import com.google.api.generator.engine.ast.ThisObjectValue; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; +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.common.AbstractTransportServiceStubClassComposer; import com.google.api.generator.gapic.composer.store.TypeStore; 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.OperationResponse; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; +import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableList; +import com.google.protobuf.TypeRegistry; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -65,6 +78,14 @@ public class HttpJsonServiceStubClassComposer extends AbstractTransportServiceSt new HttpJsonServiceStubClassComposer(); private static final TypeStore FIXED_REST_TYPESTORE = createStaticTypes(); + private static final VariableExpr TYPE_REGISTRY_VAR_EXPR = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setName("typeRegistry") + .setType(FIXED_REST_TYPESTORE.get(TypeRegistry.class.getSimpleName())) + .build()) + .build(); protected HttpJsonServiceStubClassComposer() { super(RestContext.instance()); @@ -83,11 +104,13 @@ private static TypeStore createStaticTypes() { InternalApi.class, HashMap.class, HttpJsonCallSettings.class, + HttpJsonOperationSnapshot.class, HttpJsonStubCallableFactory.class, Map.class, ProtoMessageRequestFormatter.class, ProtoMessageResponseParser.class, - ProtoRestSerializer.class)); + ProtoRestSerializer.class, + TypeRegistry.class)); } @Override @@ -97,7 +120,10 @@ protected boolean generateOperationsStubLogic(Service service) { @Override protected Statement createMethodDescriptorVariableDecl( - Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr) { + Service service, + Method protoMethod, + VariableExpr methodDescriptorVarExpr, + Map messageTypes) { MethodInvocationExpr expr = MethodInvocationExpr.builder() .setMethodName("newBuilder") @@ -122,6 +148,24 @@ protected Statement createMethodDescriptorVariableDecl( methodMaker.apply("setRequestFormatter", getRequestFormatterExpr(protoMethod)).apply(expr); expr = methodMaker.apply("setResponseParser", setResponseParserExpr(protoMethod)).apply(expr); + if (protoMethod.isOperationPollingMethod() || protoMethod.hasLro()) { + expr = + methodMaker + .apply( + "setOperationSnapshotFactory", + setOperationSnapshotFactoryExpr(protoMethod, messageTypes)) + .apply(expr); + } + + if (protoMethod.isOperationPollingMethod()) { + expr = + methodMaker + .apply( + "setPollingRequestFactory", + setPollingRequestFactoryExpr(protoMethod, messageTypes)) + .apply(expr); + } + expr = MethodInvocationExpr.builder() .setMethodName("build") @@ -143,6 +187,15 @@ protected Statement createMethodDescriptorVariableDecl( .build()); } + @Override + protected List createOperationsStubGetterMethod( + Service service, VariableExpr operationsStubVarExpr) { + if (!service.hasStandardLroMethods()) { + return Collections.emptyList(); + } + return super.createOperationsStubGetterMethod(service, operationsStubVarExpr); + } + @Override protected Expr createTransportSettingsInitExpr( Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr) { @@ -160,6 +213,13 @@ protected Expr createTransportSettingsInitExpr( .setArguments(Arrays.asList(methodDescriptorVarExpr)) .build(); + callSettingsBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(callSettingsBuilderExpr) + .setMethodName("setTypeRegistry") + .setArguments(Arrays.asList(TYPE_REGISTRY_VAR_EXPR)) + .build(); + callSettingsBuilderExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(callSettingsBuilderExpr) @@ -355,11 +415,337 @@ private List setResponseParserExpr(Method protoMethod) { .setReturnType(protoMethod.outputType()) .build())) .apply(expr); + + expr = + methodMaker + .apply("setDefaultTypeRegistry", Arrays.asList(TYPE_REGISTRY_VAR_EXPR)) + .apply(expr); expr = methodMaker.apply("build", Collections.emptyList()).apply(expr); return Collections.singletonList(expr); } + // Generates get[camelCase(fieldName)] + private String getMethodFormat(String fieldName) { + return "get" + JavaStyle.toUpperCamelCase(fieldName); + } + + // Generates set[camelCase(fieldName)] + private String setMethodFormat(String fieldName) { + return "set" + JavaStyle.toUpperCamelCase(fieldName); + } + + // Generates: [nameVar].append(":").append([requestVar].get[FieldName]()); + private ExprStatement appendField( + VariableExpr nameVar, VariableExpr requestVar, String fieldName) { + BiFunction, Function> + methodMaker = getMethodMaker(); + ValueExpr colonValueExpr = + ValueExpr.builder().setValue(StringObjectValue.builder().setValue(":").build()).build(); + MethodInvocationExpr opNameAppendColonExpr = + MethodInvocationExpr.builder() + .setMethodName("append") + .setArguments(colonValueExpr) + .setExprReferenceExpr(nameVar) + .build(); + MethodInvocationExpr getField = + MethodInvocationExpr.builder() + .setExprReferenceExpr(requestVar) + .setMethodName(getMethodFormat(fieldName)) + .build(); + opNameAppendColonExpr = + methodMaker + .apply("append", Collections.singletonList(getField)) + .apply(opNameAppendColonExpr); + return ExprStatement.withExpr(opNameAppendColonExpr); + } + + // returns var.get(num); + private MethodInvocationExpr getExpr(VariableExpr var, String num) { + return MethodInvocationExpr.builder() + .setExprReferenceExpr(var) + .setMethodName("get") + .setArguments( + ValueExpr.builder() + .setValue(PrimitiveValue.builder().setValue(num).setType(TypeNode.INT).build()) + .build()) + .build(); + } + + private List setOperationSnapshotFactoryExpr( + Method protoMethod, Map messageTypes) { + + // Generate input varibles for create() + VariableExpr requestVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(protoMethod.inputType()).setName("request").build()); + VariableExpr responseVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(protoMethod.outputType()).setName("response").build()); + + MethodInvocationExpr buildExpr; + List createBody = new ArrayList<>(4); + + TypeNode httpJsonOperationSnapshotType = + FIXED_REST_TYPESTORE.get(HttpJsonOperationSnapshot.class.getSimpleName()); + TypeNode operationSnapshotType = FIXED_TYPESTORE.get(OperationSnapshot.class.getSimpleName()); + + Message inputOperationMessage = + messageTypes.get(protoMethod.inputType().reference().fullName()); + Message outputOperationMessage = + messageTypes.get(protoMethod.outputType().reference().fullName()); + OperationResponse operationResponse = outputOperationMessage.operationResponse(); + + if (operationResponse == null) { + // AIP-151 LRO + // HttpJsonOperationSnapshot.create(response) + buildExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(httpJsonOperationSnapshotType) + .setMethodName("create") + .setArguments(responseVarExpr) + .setReturnType(operationSnapshotType) + .build(); + } else { + BiFunction, Function> + methodMaker = getMethodMaker(); + + // Generate opName + TypeNode stringBuilderType = + TypeNode.withReference(ConcreteReference.withClazz(StringBuilder.class)); + VariableExpr opNameVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(stringBuilderType).setName("opName").build()); + MethodInvocationExpr getId = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName(getMethodFormat(operationResponse.nameFieldName())) + .build(); + Expr opNameObjectExpr = + NewObjectExpr.builder().setType(stringBuilderType).setArguments(getId).build(); + AssignmentExpr opNameAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(opNameVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(opNameObjectExpr) + .build(); + createBody.add(ExprStatement.withExpr(opNameAssignExpr)); + + // Generate compound operation name + if (!protoMethod.isOperationPollingMethod()) { + // TODO: Change to ordered map + Map requestFields = inputOperationMessage.operationRequestFields(); + List fieldAnnotationNames = new ArrayList(requestFields.keySet()); + Collections.sort(fieldAnnotationNames); + for (String fieldName : fieldAnnotationNames) { + createBody.add(appendField(opNameVarExpr, requestVarExpr, requestFields.get(fieldName))); + } + } + + // Generate check for status == done + MethodInvocationExpr getStatusExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName(getMethodFormat(operationResponse.statusFieldName())) + .build(); + + String statusTypeName = operationResponse.statusFieldTypeName(); + String statusClassName = statusTypeName.substring(statusTypeName.lastIndexOf('.') + 1); + + TypeNode opType = + protoMethod.hasLro() ? protoMethod.lro().responseType() : protoMethod.outputType(); + + TypeNode statusType = + TypeNode.withReference( + VaporReference.builder() + .setName(statusClassName) + .setPakkage(opType.reference().fullName()) + .setIsStaticImport(false) + .build()); + VariableExpr statusDoneExpr = + VariableExpr.builder() + .setVariable(Variable.builder().setName("DONE").setType(TypeNode.INT).build()) + .setStaticReferenceType(statusType) + .build(); + MethodInvocationExpr statusEqualsExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(statusDoneExpr) + .setMethodName("equals") + .setArguments(getStatusExpr) + .build(); + + // Generate return statement + + // Generate getter methods from annotations + MethodInvocationExpr opNameToStringExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(opNameVarExpr) + .setMethodName("toString") + .build(); + MethodInvocationExpr getHttpErrorStatusCodeExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName(getMethodFormat(operationResponse.errorCodeFieldName())) + .build(); + MethodInvocationExpr getHttpErrorMessageExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName(getMethodFormat(operationResponse.errorMessageFieldName())) + .build(); + MethodInvocationExpr newBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(httpJsonOperationSnapshotType) + .setMethodName("newBuilder") + .build(); + + newBuilderExpr = + methodMaker + .apply("setName", Collections.singletonList(opNameToStringExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setMetadata", Collections.singletonList(responseVarExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setDone", Collections.singletonList(statusEqualsExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setResponse", Collections.singletonList(responseVarExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setError", Arrays.asList(getHttpErrorStatusCodeExpr, getHttpErrorMessageExpr)) + .apply(newBuilderExpr); + + buildExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(newBuilderExpr) + .setMethodName("build") + .setReturnType(operationSnapshotType) + .build(); + } + // Generate lambda anonymous class + return Collections.singletonList( + LambdaExpr.builder() + .setArguments( + requestVarExpr.toBuilder().setIsDecl(true).build(), + responseVarExpr.toBuilder().setIsDecl(true).build()) + .setBody(createBody) + .setReturnExpr(buildExpr) + .build()); + } + + private List setPollingRequestFactoryExpr( + Method protoMethod, Map messageTypes) { + BiFunction, Function> + methodMaker = getMethodMaker(); + + Message inputOperationMessage = + messageTypes.get(protoMethod.inputType().reference().fullName()); + + List createBody = new ArrayList(1); + + // Generate input variables for create + VariableExpr compoundOperationIdVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder().setType(TypeNode.STRING).setName("compoundOperationId").build()) + .build(); + + // Generate idComponenets + TypeNode listStringType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(List.class) + .setGenerics(ConcreteReference.withClazz(String.class)) + .build()); + TypeNode arrayListStringType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(ArrayList.class) + .setGenerics(ConcreteReference.withClazz(String.class)) + .build()); + TypeNode arraysType = TypeNode.withReference(ConcreteReference.withClazz(Arrays.class)); + VariableExpr idComponentsVarExpr = + VariableExpr.withVariable( + Variable.builder().setName("idComponents").setType(listStringType).build()); + MethodInvocationExpr compoundOperationIdSplitExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(compoundOperationIdVarExpr) + .setMethodName("split") + .setArguments(ValueExpr.withValue(StringObjectValue.withValue(":"))) + .setReturnType(arrayListStringType) + .build(); + MethodInvocationExpr asListExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(arraysType) + .setMethodName("asList") + .setArguments(compoundOperationIdSplitExpr) + .setReturnType(arrayListStringType) + .build(); + AssignmentExpr idComponentsAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(idComponentsVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(asListExpr) + .build(); + createBody.add(ExprStatement.withExpr(idComponentsAssignExpr)); + + // Generate return statement + TypeNode getOperationRequestType = TypeNode.withReference(protoMethod.inputType().reference()); + MethodInvocationExpr newBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(getOperationRequestType) + .setMethodName("newBuilder") + .build(); + BiMap responseFieldsMap = inputOperationMessage.operationResponseFields(); + List responseFieldAnnotationNames = new ArrayList(responseFieldsMap.keySet()); + Collections.sort(responseFieldAnnotationNames); + Set responseFieldsNames = responseFieldsMap.inverse().keySet(); + Set allFieldsNames = inputOperationMessage.fieldMap().keySet(); + ArrayList nonResponseFieldsNames = new ArrayList(); + for (String fieldName : allFieldsNames) { + if (!responseFieldsNames.contains(fieldName)) { + nonResponseFieldsNames.add(fieldName); + } + } + Collections.sort(nonResponseFieldsNames); + int index = 0; + for (String fieldAnnotationName : responseFieldAnnotationNames) { + newBuilderExpr = + methodMaker + .apply( + setMethodFormat(responseFieldsMap.get(fieldAnnotationName)), + Collections.singletonList(getExpr(idComponentsVarExpr, Integer.toString(index)))) + .apply(newBuilderExpr); + index++; + } + for (String fieldName : nonResponseFieldsNames) { + newBuilderExpr = + methodMaker + .apply( + setMethodFormat(fieldName), + Collections.singletonList(getExpr(idComponentsVarExpr, Integer.toString(index)))) + .apply(newBuilderExpr); + index++; + } + + MethodInvocationExpr buildExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(newBuilderExpr) + .setMethodName("build") + .setReturnType(getOperationRequestType) + .build(); + + // Return lambda anonymous class + return Collections.singletonList( + LambdaExpr.builder() + .setArguments(compoundOperationIdVarExpr.toBuilder().setIsDecl(true).build()) + .setBody(createBody) + .setReturnExpr(buildExpr) + .build()); + } + private Expr createBodyFieldsExtractorClassInstance( Method method, TypeNode extractorReturnType, @@ -593,6 +979,119 @@ private List getHttpMethodTypeExpr(Method protoMethod) { } @Override + protected List createOperationsStubInitExpr( + Service service, + Expr thisExpr, + VariableExpr operationsStubClassVarExpr, + VariableExpr clientContextVarExpr, + VariableExpr callableFactoryVarExpr) { + TypeNode operationsStubType = getTransportOperationsStubType(service); + String standardOpStub = HttpJsonOperationsStub.class.getName(); + + List arguments = + new ArrayList<>(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr)); + if (standardOpStub.equals(operationsStubType.reference().fullName())) { + arguments.add(TYPE_REGISTRY_VAR_EXPR); + } + + return Collections.singletonList( + AssignmentExpr.builder() + .setVariableExpr( + operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) + .setValueExpr( + MethodInvocationExpr.builder() + .setStaticReferenceType(operationsStubType) + .setMethodName("create") + .setArguments(arguments) + .setReturnType(operationsStubClassVarExpr.type()) + .build()) + .build()); + } + + @Override + protected List createLongRunningClient(Service service, TypeStore typeStore) { + Method pollingMethod = service.operationPollingMethod(); + if (pollingMethod != null) { + Expr thisExpr = + ValueExpr.withValue( + ThisObjectValue.withType( + typeStore.get( + getTransportContext() + .classNames() + .getTransportServiceStubClassName(service)))); + + VariableExpr callable = + VariableExpr.withVariable( + Variable.builder() + .setName(pollingMethod.name().toLowerCase() + "Callable") + .setType(TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) + .build()); + VariableExpr methodDescriptor = + VariableExpr.withVariable( + Variable.builder() + .setName(pollingMethod.name().toLowerCase() + "MethodDescriptor") + .setType( + TypeNode.withReference( + ConcreteReference.withClazz(ApiMethodDescriptor.class))) + .build()); + + TypeNode httpJsonLongRunningClientType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(HttpJsonLongRunningClient.class) + .setGenerics( + Arrays.asList( + pollingMethod.inputType().reference(), + pollingMethod.outputType().reference())) + .build()); + + NewObjectExpr HttpJsonLongRunningClient = + NewObjectExpr.builder() + .setType(httpJsonLongRunningClientType) + .setArguments( + Arrays.asList( + callable, + MethodInvocationExpr.builder() + .setExprReferenceExpr(methodDescriptor) + .setMethodName("getOperationSnapshotFactory") + .build(), + MethodInvocationExpr.builder() + .setExprReferenceExpr(methodDescriptor) + .setMethodName("getPollingRequestFactory") + .build())) + .build(); + + AssignmentExpr assignLongRunningClient = + AssignmentExpr.builder() + .setVariableExpr( + VariableExpr.builder() + .setExprReferenceExpr(thisExpr) + .setVariable( + Variable.builder() + .setName("longRunningClient") + .setType( + TypeNode.withReference( + ConcreteReference.withClazz(LongRunningClient.class))) + .build()) + .build()) + .setValueExpr(HttpJsonLongRunningClient) + .build(); + + return Arrays.asList(ExprStatement.withExpr(assignLongRunningClient)); + } else { + return Collections.emptyList(); + } + } + + @Override + protected VariableExpr declareLongRunningClient() { + return VariableExpr.withVariable( + Variable.builder() + .setName("longRunningClient") + .setType(TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class))) + .build()); + } + protected Optional getCallableCreatorMethodName(TypeNode callableVarExprType) { final String typeName = callableVarExprType.reference().name(); String streamName = "Unary"; @@ -614,4 +1113,61 @@ protected Optional getCallableCreatorMethodName(TypeNode callableVarExpr } return Optional.of(String.format("create%sCallable", streamName)); } + + @Override + protected List createTypeRegistry(Service service) { + TypeNode typeRegistryType = FIXED_REST_TYPESTORE.get(TypeRegistry.class.getSimpleName()); + + VariableExpr typeRegistryVarExpr = + TYPE_REGISTRY_VAR_EXPR + .toBuilder() + .setIsDecl(true) + .setIsStatic(true) + .setScope(ScopeNode.PRIVATE) + .setIsFinal(true) + .build(); + + Map anyTypes = new HashMap<>(); + for (Method method : service.methods()) { + if (method.hasLro()) { + TypeNode anyType = method.lro().responseType(); + anyTypes.put(anyType.reference().fullName(), anyType); + anyType = method.lro().metadataType(); + anyTypes.put(anyType.reference().fullName(), anyType); + } + } + + Expr typeRegistryBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(typeRegistryType) + .setMethodName("newBuilder") + .build(); + + for (TypeNode anyType : anyTypes.values()) { + typeRegistryBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(typeRegistryBuilderExpr) + .setMethodName("add") + .setArguments( + MethodInvocationExpr.builder() + .setStaticReferenceType(anyType) + .setMethodName("getDescriptor") + .build()) + .build(); + } + + typeRegistryBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(typeRegistryBuilderExpr) + .setMethodName("build") + .setReturnType(typeRegistryType) + .build(); + + return Collections.singletonList( + ExprStatement.withExpr( + AssignmentExpr.builder() + .setVariableExpr(typeRegistryVarExpr) + .setValueExpr(typeRegistryBuilderExpr) + .build())); + } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java b/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java index eab59215bf..2502a9128e 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java @@ -14,7 +14,6 @@ package com.google.api.generator.gapic.composer.rest; -import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.httpjson.ApiMethodDescriptor; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; @@ -24,6 +23,7 @@ import com.google.api.gax.httpjson.ProtoOperationTransformers; import com.google.api.gax.httpjson.longrunning.OperationsClient; import com.google.api.gax.httpjson.longrunning.stub.HttpJsonOperationsStub; +import com.google.api.gax.httpjson.longrunning.stub.OperationsStub; import com.google.api.generator.gapic.composer.common.TransportContext; import com.google.api.generator.gapic.composer.utils.ClassNames; import com.google.api.generator.gapic.model.Transport; @@ -58,7 +58,7 @@ public abstract class RestContext extends TransportContext { .setTransportCallSettingsType(classToType(HttpJsonCallSettings.class)) .setTransportCallableFactoryType(classToType(HttpJsonCallableFactory.class)) // TODO: set to com.google.api.gax.httpjson.longrunning.stub.OperationsStub.class - .setOperationsStubTypes(ImmutableList.of(classToType(BackgroundResource.class))) + .setOperationsStubTypes(ImmutableList.of(classToType(OperationsStub.class))) .setTransportCallSettingsName("httpJsonCallSettings") // For RetrySettingsComposer .setOperationResponseTransformerType( diff --git a/src/main/java/com/google/api/generator/gapic/model/LongrunningOperation.java b/src/main/java/com/google/api/generator/gapic/model/LongrunningOperation.java index c2b425e2f8..e23e8a6ee3 100644 --- a/src/main/java/com/google/api/generator/gapic/model/LongrunningOperation.java +++ b/src/main/java/com/google/api/generator/gapic/model/LongrunningOperation.java @@ -16,6 +16,7 @@ import com.google.api.generator.engine.ast.TypeNode; import com.google.auto.value.AutoValue; +import javax.annotation.Nullable; @AutoValue public abstract class LongrunningOperation { @@ -23,22 +24,21 @@ public abstract class LongrunningOperation { public abstract TypeNode metadataType(); - public static LongrunningOperation withTypes(TypeNode responseType, TypeNode metadataType) { - return builder().setResponseType(responseType).setMetadataType(metadataType).build(); - } + @Nullable + public abstract TypeNode operationServiceStubType(); - // Private. - static Builder builder() { + public static Builder builder() { return new AutoValue_LongrunningOperation.Builder(); } - // Private. @AutoValue.Builder - abstract static class Builder { - abstract Builder setResponseType(TypeNode responseType); + public abstract static class Builder { + public abstract Builder setResponseType(TypeNode responseType); + + public abstract Builder setMetadataType(TypeNode metadataType); - abstract Builder setMetadataType(TypeNode metadataType); + public abstract Builder setOperationServiceStubType(TypeNode operationServiceType); - abstract LongrunningOperation build(); + public abstract LongrunningOperation build(); } } diff --git a/src/main/java/com/google/api/generator/gapic/model/Message.java b/src/main/java/com/google/api/generator/gapic/model/Message.java index c58e62582e..91a5388e37 100644 --- a/src/main/java/com/google/api/generator/gapic/model/Message.java +++ b/src/main/java/com/google/api/generator/gapic/model/Message.java @@ -18,6 +18,8 @@ import com.google.api.generator.engine.ast.Reference; import com.google.api.generator.engine.ast.TypeNode; import com.google.auto.value.AutoValue; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.util.Arrays; @@ -51,6 +53,13 @@ public abstract class Message { public abstract ImmutableMap fieldMap(); + @Nullable + public abstract OperationResponse operationResponse(); + + public abstract Map operationRequestFields(); + + public abstract BiMap operationResponseFields(); + // The resource name annotation (and definition) in this message. Optional. // Expected dto be empty for messages that have no such definition. @Nullable @@ -103,7 +112,9 @@ public static Builder builder() { .setOuterNestedTypes(Collections.emptyList()) .setFields(Collections.emptyList()) .setFieldMap(Collections.emptyMap()) - .setEnumValues(Collections.emptyMap()); + .setEnumValues(Collections.emptyMap()) + .setOperationResponseFields(HashBiMap.create()) + .setOperationRequestFields(Collections.emptyMap()); } @AutoValue.Builder @@ -129,6 +140,13 @@ public Builder setEnumValues(List names, List numbers) { public abstract Builder setOuterNestedTypes(List outerNestedTypes); + public abstract Builder setOperationResponse(OperationResponse operationResponse); + + public abstract Builder setOperationRequestFields(Map operationRequestFields); + + public abstract Builder setOperationResponseFields( + BiMap operationRequestFields); + abstract Builder setFieldMap(Map fieldMap); abstract ImmutableList fields(); diff --git a/src/main/java/com/google/api/generator/gapic/model/Method.java b/src/main/java/com/google/api/generator/gapic/model/Method.java index 56a1403098..286bd8c84e 100644 --- a/src/main/java/com/google/api/generator/gapic/model/Method.java +++ b/src/main/java/com/google/api/generator/gapic/model/Method.java @@ -66,6 +66,8 @@ public boolean isPaged() { // [["content", "error"], ["content", "error", "info"]]. public abstract ImmutableList> methodSignatures(); + public abstract boolean operationPollingMethod(); + public boolean hasLro() { return lro() != null; } @@ -82,6 +84,10 @@ public boolean isMixin() { return mixedInApiName() != null; } + public boolean isOperationPollingMethod() { + return operationPollingMethod(); + } + public abstract Builder toBuilder(); public static Builder builder() { @@ -89,7 +95,8 @@ public static Builder builder() { .setStream(Stream.NONE) .setMethodSignatures(ImmutableList.of()) .setIsBatching(false) - .setIsDeprecated(false); + .setIsDeprecated(false) + .setOperationPollingMethod(false); } public static Stream toStream(boolean isClientStreaming, boolean isServerStreaming) { @@ -131,6 +138,8 @@ public abstract static class Builder { public abstract Builder setIsDeprecated(boolean isDeprecated); + public abstract Builder setOperationPollingMethod(boolean operationPollingMethod); + public abstract Method build(); } } diff --git a/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java b/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java new file mode 100644 index 0000000000..9ad5ac385f --- /dev/null +++ b/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java @@ -0,0 +1,50 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.api.generator.gapic.model; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class OperationResponse { + public abstract String nameFieldName(); + + public abstract String statusFieldName(); + + public abstract String errorCodeFieldName(); + + public abstract String errorMessageFieldName(); + + public abstract String statusFieldTypeName(); + + public static Builder builder() { + return new AutoValue_OperationResponse.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder setNameFieldName(String nameFieldName); + + public abstract Builder setStatusFieldName(String val); + + public abstract Builder setErrorCodeFieldName(String val); + + public abstract Builder setErrorMessageFieldName(String val); + + public abstract Builder setStatusFieldTypeName(String className); + + public abstract OperationResponse build(); + } +} diff --git a/src/main/java/com/google/api/generator/gapic/model/Service.java b/src/main/java/com/google/api/generator/gapic/model/Service.java index 2ce5c09d2e..34d3f97b25 100644 --- a/src/main/java/com/google/api/generator/gapic/model/Service.java +++ b/src/main/java/com/google/api/generator/gapic/model/Service.java @@ -14,6 +14,7 @@ package com.google.api.generator.gapic.model; +import com.google.api.generator.engine.ast.TypeNode; import com.google.auto.value.AutoValue; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; @@ -49,6 +50,35 @@ public boolean hasDescription() { return !Strings.isNullOrEmpty(description()); } + public Method operationPollingMethod() { + for (Method method : methods()) { + if (method.isOperationPollingMethod()) { + return method; + } + } + return null; + } + + public TypeNode operationServiceStubType() { + for (Method method : methods()) { + if (method.hasLro() && method.lro().operationServiceStubType() != null) { + // All methods within the same service must have the same operationServiceTypeName if + // present + return method.lro().operationServiceStubType(); + } + } + return null; + } + + public TypeNode operationType() { + for (Method method : methods()) { + if (method.hasLro() && method.lro().operationServiceStubType() != null) { + return method.outputType(); + } + } + return null; + } + public boolean hasLroMethods() { for (Method method : methods()) { if (method.hasLro()) { @@ -58,6 +88,15 @@ public boolean hasLroMethods() { return false; } + public boolean hasStandardLroMethods() { + for (Method method : methods()) { + if (method.hasLro() && method.lro().operationServiceStubType() == null) { + return true; + } + } + return false; + } + public abstract Builder toBuilder(); public static Builder builder() { diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/BUILD.bazel b/src/main/java/com/google/api/generator/gapic/protoparser/BUILD.bazel index 6cccdd373a..904b7fbf2b 100644 --- a/src/main/java/com/google/api/generator/gapic/protoparser/BUILD.bazel +++ b/src/main/java/com/google/api/generator/gapic/protoparser/BUILD.bazel @@ -30,6 +30,7 @@ java_library( "@com_google_code_findbugs_jsr305//jar", "@com_google_code_gson//jar", "@com_google_googleapis//google/api:api_java_proto", + "@com_google_googleapis//google/cloud:extended_operations_java_proto", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_guava_guava//jar", "@com_google_protobuf//:protobuf_java", diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java index 8fd376b7e0..0338de6374 100644 --- a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java +++ b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java @@ -20,6 +20,7 @@ import com.google.api.ResourceDescriptor; import com.google.api.ResourceProto; import com.google.api.generator.engine.ast.TypeNode; +import com.google.api.generator.engine.ast.VaporReference; import com.google.api.generator.gapic.model.Field; import com.google.api.generator.gapic.model.GapicBatchingSettings; import com.google.api.generator.gapic.model.GapicContext; @@ -30,15 +31,20 @@ import com.google.api.generator.gapic.model.LongrunningOperation; import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; +import com.google.api.generator.gapic.model.OperationResponse; import com.google.api.generator.gapic.model.ResourceName; import com.google.api.generator.gapic.model.ResourceReference; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.model.SourceCodeInfoLocation; import com.google.api.generator.gapic.model.Transport; import com.google.api.generator.gapic.utils.ResourceNameConstants; +import com.google.cloud.ExtendedOperationsProto; +import com.google.cloud.OperationResponseMapping; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.base.Strings; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.longrunning.OperationInfo; @@ -552,6 +558,38 @@ private static Map parseMessages( } } TypeNode messageType = TypeParser.parseType(messageDescriptor); + + List fields = messageDescriptor.getFields(); + HashMap operationRequestFields = new HashMap(); + BiMap operationResponseFields = HashBiMap.create(); + OperationResponse.Builder operationResponse = null; + for (FieldDescriptor fd : fields) { + if (fd.getOptions().hasExtension(ExtendedOperationsProto.operationRequestField)) { + String orf = fd.getOptions().getExtension(ExtendedOperationsProto.operationRequestField); + operationRequestFields.put(orf, fd.getName()); + } + if (fd.getOptions().hasExtension(ExtendedOperationsProto.operationResponseField)) { + String orf = fd.getOptions().getExtension(ExtendedOperationsProto.operationResponseField); + operationResponseFields.put(orf, fd.getName()); + } + if (fd.getOptions().hasExtension(ExtendedOperationsProto.operationField)) { + OperationResponseMapping orm = + fd.getOptions().getExtension(ExtendedOperationsProto.operationField); + if (operationResponse == null) { + operationResponse = OperationResponse.builder(); + } + if (orm.equals(OperationResponseMapping.NAME)) { + operationResponse.setNameFieldName(fd.getName()); + } else if (orm.equals(OperationResponseMapping.STATUS)) { + operationResponse.setStatusFieldName(fd.getName()); + operationResponse.setStatusFieldTypeName(fd.toProto().getTypeName()); + } else if (orm.equals(OperationResponseMapping.ERROR_CODE)) { + operationResponse.setErrorCodeFieldName(fd.getName()); + } else if (orm.equals(OperationResponseMapping.ERROR_MESSAGE)) { + operationResponse.setErrorMessageFieldName(fd.getName()); + } + } + } messages.put( messageType.reference().fullName(), Message.builder() @@ -560,6 +598,9 @@ private static Map parseMessages( .setFullProtoName(messageDescriptor.getFullName()) .setFields(parseFields(messageDescriptor, outputResourceReferencesSeen)) .setOuterNestedTypes(outerNestedTypes) + .setOperationRequestFields(operationRequestFields) + .setOperationResponseFields(operationResponseFields) + .setOperationResponse(operationResponse != null ? operationResponse.build() : null) .build()); return messages; } @@ -662,6 +703,12 @@ static List parseMethods( serviceDescriptor.getName(), protoMethod.getName()); + boolean operationPollingMethod = + protoMethod.getOptions().hasExtension(ExtendedOperationsProto.operationPollingMethod) + ? protoMethod + .getOptions() + .getExtension(ExtendedOperationsProto.operationPollingMethod) + : false; methods.add( methodBuilder .setName(protoMethod.getName()) @@ -669,7 +716,7 @@ static List parseMethods( .setOutputType(TypeParser.parseType(protoMethod.getOutputType())) .setStream( Method.toStream(protoMethod.isClientStreaming(), protoMethod.isServerStreaming())) - .setLro(parseLro(protoMethod, messageTypes)) + .setLro(parseLro(servicePackage, protoMethod, messageTypes)) .setMethodSignatures( MethodSignatureParser.parseMethodSignatures( protoMethod, @@ -682,6 +729,7 @@ static List parseMethods( .setIsBatching(isBatching) .setPageSizeFieldName(parsePageSizeFieldName(protoMethod, messageTypes, transport)) .setIsDeprecated(isDeprecated) + .setOperationPollingMethod(operationPollingMethod) .build()); // Any input type that has a resource reference will need a resource name helper class. @@ -723,18 +771,43 @@ static List parseMethods( @VisibleForTesting static LongrunningOperation parseLro( - MethodDescriptor methodDescriptor, Map messageTypes) { + String servicePackage, MethodDescriptor methodDescriptor, Map messageTypes) { MethodOptions methodOptions = methodDescriptor.getOptions(); - if (!methodOptions.hasExtension(OperationsProto.operationInfo)) { - return null; + + TypeNode operationServiceStubType = null; + String responseTypeName = null; + String metadataTypeName = null; + + if (methodOptions.hasExtension(OperationsProto.operationInfo)) { + OperationInfo lroInfo = + methodDescriptor.getOptions().getExtension(OperationsProto.operationInfo); + responseTypeName = lroInfo.getResponseType(); + metadataTypeName = lroInfo.getMetadataType(); + } + if (methodOptions.hasExtension(ExtendedOperationsProto.operationService)) { + // TODO: support full package name for operations_service annotation value + String opServiceName = methodOptions.getExtension(ExtendedOperationsProto.operationService); + operationServiceStubType = + TypeNode.withReference( + VaporReference.builder() + .setName(opServiceName + "Stub") + .setPakkage(servicePackage + ".stub") + .build()); + + if (responseTypeName == null) { + responseTypeName = methodDescriptor.getOutputType().getFullName(); + } + if (metadataTypeName == null) { + metadataTypeName = methodDescriptor.getOutputType().getFullName(); + } } - OperationInfo lroInfo = - methodDescriptor.getOptions().getExtension(OperationsProto.operationInfo); + if (responseTypeName == null || metadataTypeName == null) { + return null; + } - // These can be short names (e.g. FooMessage) or fully-qualified names with the *proto* package. - String responseTypeName = lroInfo.getResponseType(); - String metadataTypeName = lroInfo.getMetadataType(); + Message responseMessage = null; + Message metadataMessage = null; int lastDotIndex = responseTypeName.lastIndexOf('.'); boolean isResponseTypeNameShortOnly = lastDotIndex < 0; @@ -746,9 +819,6 @@ static LongrunningOperation parseLro( String metadataTypeShortName = lastDotIndex >= 0 ? metadataTypeName.substring(lastDotIndex + 1) : metadataTypeName; - Message responseMessage = null; - Message metadataMessage = null; - // The messageTypes map keys to the Java fully-qualified name. for (Map.Entry messageEntry : messageTypes.entrySet()) { String messageKey = messageEntry.getKey(); @@ -791,7 +861,11 @@ static LongrunningOperation parseLro( "LRO metadata message %s not found in method %s", metadataTypeName, methodDescriptor.getName())); - return LongrunningOperation.withTypes(responseMessage.type(), metadataMessage.type()); + return LongrunningOperation.builder() + .setResponseType(responseMessage.type()) + .setMetadataType(metadataMessage.type()) + .setOperationServiceStubType(operationServiceStubType) + .build(); } @VisibleForTesting diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden index 7d6032778d..6f5e7eab3b 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden @@ -1,11 +1,11 @@ package com.google.showcase.v1beta1.stub; import com.google.api.core.BetaApi; -import com.google.api.gax.core.BackgroundResource; -import com.google.api.gax.httpjson.ApiMessage; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; +import com.google.api.gax.httpjson.longrunning.stub.OperationsStub; import com.google.api.gax.rpc.BatchingCallSettings; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.OperationCallSettings; @@ -13,6 +13,7 @@ import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; +import com.google.longrunning.Operation; import javax.annotation.Generated; // AUTO-GENERATED DOCUMENTATION AND CLASS. @@ -24,7 +25,7 @@ import javax.annotation.Generated; @BetaApi @Generated("by gapic-generator-java") public class HttpJsonComplianceCallableFactory - implements HttpJsonStubCallableFactory { + implements HttpJsonStubCallableFactory { @Override public UnaryCallable createUnaryCallable( @@ -59,10 +60,18 @@ public class HttpJsonComplianceCallableFactory @Override public OperationCallable createOperationCallable( - HttpJsonCallSettings httpJsonCallSettings, + HttpJsonCallSettings httpJsonCallSettings, OperationCallSettings callSettings, ClientContext clientContext, - BackgroundResource operationsStub) { - return null; + OperationsStub operationsStub) { + UnaryCallable innerCallable = + HttpJsonCallableFactory.createBaseUnaryCallable( + httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); + HttpJsonOperationSnapshotCallable initialCallable = + new HttpJsonOperationSnapshotCallable( + innerCallable, + httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); + return HttpJsonCallableFactory.createOperationCallable( + callSettings, clientContext, operationsStub.longRunningClient(), initialCallable); } } diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden index 331e5bf961..6b6a701df9 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden @@ -13,6 +13,7 @@ import com.google.api.gax.httpjson.ProtoMessageResponseParser; import com.google.api.gax.httpjson.ProtoRestSerializer; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.UnaryCallable; +import com.google.protobuf.TypeRegistry; import com.google.showcase.v1beta1.RepeatRequest; import com.google.showcase.v1beta1.RepeatResponse; import java.io.IOException; @@ -33,6 +34,8 @@ import javax.annotation.Generated; @Generated("by gapic-generator-java") @BetaApi("A restructuring of stub classes is planned, so this may break in the future") public class HttpJsonComplianceStub extends ComplianceStub { + private static final TypeRegistry typeRegistry = TypeRegistry.newBuilder().build(); + private static final ApiMethodDescriptor repeatDataBodyMethodDescriptor = ApiMethodDescriptor.newBuilder() @@ -62,6 +65,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -96,6 +100,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -130,6 +135,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -176,6 +182,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -220,6 +227,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -261,6 +269,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -315,27 +324,33 @@ public class HttpJsonComplianceStub extends ComplianceStub { HttpJsonCallSettings repeatDataBodyTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataBodyMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataBodyInfoTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataBodyInfoMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataQueryTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataQueryMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataSimplePathTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataSimplePathMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataPathResourceTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataPathResourceMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataPathTrailingResourceTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataPathTrailingResourceMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); this.repeatDataBodyCallable = diff --git a/src/test/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposerTest.java index 59eb3536be..397e0ec2c2 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposerTest.java +++ b/src/test/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposerTest.java @@ -102,7 +102,11 @@ public void composeClassHeaderMethodSampleCode_firstMethodIsNotUnaryRpc() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); TypeNode ttlTypeNode = TypeNode.withReference( VaporReference.builder().setName("Duration").setPakkage(PROTO_PACKAGE_NAME).build()); @@ -1250,7 +1254,11 @@ public void validComposeRpcMethodHeaderSampleCode_lroUnaryRpcWithNoMethodArgumen .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -1303,7 +1311,11 @@ public void validComposeRpcMethodHeaderSampleCode_lroRpcWithReturnResponseType() .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); TypeNode ttlTypeNode = TypeNode.withReference( VaporReference.builder().setName("Duration").setPakkage(PROTO_PACKAGE_NAME).build()); @@ -1370,7 +1382,11 @@ public void validComposeRpcMethodHeaderSampleCode_lroRpcWithReturnVoid() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); TypeNode ttlTypeNode = TypeNode.withReference( VaporReference.builder().setName("Duration").setPakkage(PROTO_PACKAGE_NAME).build()); @@ -1526,7 +1542,11 @@ public void validComposeRpcDefaultMethodHeaderSampleCode_hasLroMethodWithReturnR .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -1579,7 +1599,11 @@ public void validComposeRpcDefaultMethodHeaderSampleCode_hasLroMethodWithReturnV .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -1730,7 +1754,11 @@ public void validComposeLroCallableMethodHeaderSampleCode_withReturnResponse() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -1782,7 +1810,11 @@ public void validComposeLroCallableMethodHeaderSampleCode_withReturnVoid() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -2346,7 +2378,11 @@ public void validComposeRegularCallableMethodHeaderSampleCode_lroRpc() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -2397,7 +2433,11 @@ public void validComposeRegularCallableMethodHeaderSampleCode_lroRpcWithReturnVo .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") diff --git a/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java b/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java index 9026437b6d..428b5156d9 100644 --- a/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java +++ b/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java @@ -201,7 +201,7 @@ public void parseLro_missingResponseType() { assertEquals("Wait", waitMethodDescriptor.getName()); messageTypes.remove("com.google.showcase.v1beta1.WaitResponse"); assertThrows( - NullPointerException.class, () -> Parser.parseLro(waitMethodDescriptor, messageTypes)); + NullPointerException.class, () -> Parser.parseLro("", waitMethodDescriptor, messageTypes)); } @Test @@ -211,7 +211,7 @@ public void parseLro_missingMetadataType() { assertEquals("Wait", waitMethodDescriptor.getName()); messageTypes.remove("com.google.showcase.v1beta1.WaitMetadata"); assertThrows( - NullPointerException.class, () -> Parser.parseLro(waitMethodDescriptor, messageTypes)); + NullPointerException.class, () -> Parser.parseLro("", waitMethodDescriptor, messageTypes)); } @Test diff --git a/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel index 1a5133b74c..ecbdd6a532 100644 --- a/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel +++ b/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel @@ -56,6 +56,7 @@ proto_library( "@com_google_googleapis//google/api:client_proto", "@com_google_googleapis//google/api:field_behavior_proto", "@com_google_googleapis//google/api:resource_proto", + "@com_google_googleapis//google/cloud:extended_operations_proto", "@com_google_googleapis//google/longrunning:operations_proto", "@com_google_googleapis//google/rpc:error_details_proto", "@com_google_googleapis//google/rpc:status_proto", diff --git a/src/test/java/com/google/api/generator/gapic/testdata/compliance.proto b/src/test/java/com/google/api/generator/gapic/testdata/compliance.proto index c602452b13..4467a387ab 100644 --- a/src/test/java/com/google/api/generator/gapic/testdata/compliance.proto +++ b/src/test/java/com/google/api/generator/gapic/testdata/compliance.proto @@ -16,6 +16,7 @@ syntax = "proto3"; import "google/api/annotations.proto"; import "google/api/client.proto"; +import "google/cloud/extended_operations.proto"; package google.showcase.v1beta1; diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClient.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClient.java index 1860b0cca4..af1cc6dd1f 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClient.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClient.java @@ -54,6 +54,7 @@ * .addAllAssetNames(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setReadTimeWindow(TimeWindow.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * BatchGetAssetsHistoryResponse response = assetServiceClient.batchGetAssetsHistory(request); * } @@ -190,6 +191,7 @@ public final OperationsClient getOperationsClient() { * .addAllAssetTypes(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setOutputConfig(OutputConfig.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * ExportAssetsResponse response = assetServiceClient.exportAssetsAsync(request).get(); * } @@ -225,6 +227,7 @@ public final OperationFuture exportAs * .addAllAssetTypes(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setOutputConfig(OutputConfig.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * OperationFuture future = * assetServiceClient.exportAssetsOperationCallable().futureCall(request); @@ -260,6 +263,7 @@ public final OperationFuture exportAs * .addAllAssetTypes(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setOutputConfig(OutputConfig.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * ApiFuture future = assetServiceClient.exportAssetsCallable().futureCall(request); * // Do something. @@ -340,6 +344,7 @@ public final ListAssetsPagedResponse listAssets(String parent) { * .setContentType(ContentType.forNumber(0)) * .setPageSize(883849137) * .setPageToken("pageToken873572522") + * .addAllRelationshipTypes(new ArrayList()) * .build(); * for (Asset element : assetServiceClient.listAssets(request).iterateAll()) { * // doThingsWith(element); @@ -370,6 +375,7 @@ public final ListAssetsPagedResponse listAssets(ListAssetsRequest request) { * .setContentType(ContentType.forNumber(0)) * .setPageSize(883849137) * .setPageToken("pageToken873572522") + * .addAllRelationshipTypes(new ArrayList()) * .build(); * ApiFuture future = assetServiceClient.listAssetsPagedCallable().futureCall(request); * // Do something. @@ -399,6 +405,7 @@ public final UnaryCallable listAsset * .setContentType(ContentType.forNumber(0)) * .setPageSize(883849137) * .setPageToken("pageToken873572522") + * .addAllRelationshipTypes(new ArrayList()) * .build(); * while (true) { * ListAssetsResponse response = assetServiceClient.listAssetsCallable().call(request); @@ -437,6 +444,7 @@ public final UnaryCallable listAssetsCall * .addAllAssetNames(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setReadTimeWindow(TimeWindow.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * BatchGetAssetsHistoryResponse response = assetServiceClient.batchGetAssetsHistory(request); * } @@ -468,6 +476,7 @@ public final BatchGetAssetsHistoryResponse batchGetAssetsHistory( * .addAllAssetNames(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setReadTimeWindow(TimeWindow.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * ApiFuture future = * assetServiceClient.batchGetAssetsHistoryCallable().futureCall(request); @@ -924,8 +933,8 @@ public final UnaryCallable deleteFeedCallable() { *
  • `kmsKey:key` to find Cloud resources encrypted with a customer-managed encryption key * whose name contains the word "key". *
  • `state:ACTIVE` to find Cloud resources whose state contains "ACTIVE" as a word. - *
  • `NOT state:ACTIVE` to find {{gcp_name}} resources whose state doesn't contain - * "ACTIVE" as a word. + *
  • `NOT state:ACTIVE` to find Cloud resources whose state doesn't contain "ACTIVE" as a + * word. *
  • `createTime<1609459200` to find Cloud resources that were created before * "2021-01-01 00:00:00 UTC". 1609459200 is the epoch timestamp of "2021-01-01 00:00:00 * UTC" in seconds. @@ -985,6 +994,7 @@ public final SearchAllResourcesPagedResponse searchAllResources( * .setPageSize(883849137) * .setPageToken("pageToken873572522") * .setOrderBy("orderBy-1207110587") + * .setReadMask(FieldMask.newBuilder().build()) * .build(); * for (ResourceSearchResult element : * assetServiceClient.searchAllResources(request).iterateAll()) { @@ -1019,6 +1029,7 @@ public final SearchAllResourcesPagedResponse searchAllResources( * .setPageSize(883849137) * .setPageToken("pageToken873572522") * .setOrderBy("orderBy-1207110587") + * .setReadMask(FieldMask.newBuilder().build()) * .build(); * ApiFuture future = * assetServiceClient.searchAllResourcesPagedCallable().futureCall(request); @@ -1052,6 +1063,7 @@ public final SearchAllResourcesPagedResponse searchAllResources( * .setPageSize(883849137) * .setPageToken("pageToken873572522") * .setOrderBy("orderBy-1207110587") + * .setReadMask(FieldMask.newBuilder().build()) * .build(); * while (true) { * SearchAllResourcesResponse response = @@ -1314,8 +1326,8 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * [AnalyzeIamPolicyResponse][google.cloud.asset.v1.AnalyzeIamPolicyResponse]. This method * implements the [google.longrunning.Operation][google.longrunning.Operation], which allows you * to track the operation status. We recommend intervals of at least 2 seconds with exponential - * backoff retry to poll the operation result. The metadata contains the request to help callers - * to map responses to requests. + * backoff retry to poll the operation result. The metadata contains the metadata for the + * long-running operation. * *

    Sample code: * @@ -1335,7 +1347,7 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ public final OperationFuture< - AnalyzeIamPolicyLongrunningResponse, AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningResponse, AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningAsync(AnalyzeIamPolicyLongrunningRequest request) { return analyzeIamPolicyLongrunningOperationCallable().futureCall(request); } @@ -1348,8 +1360,8 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * [AnalyzeIamPolicyResponse][google.cloud.asset.v1.AnalyzeIamPolicyResponse]. This method * implements the [google.longrunning.Operation][google.longrunning.Operation], which allows you * to track the operation status. We recommend intervals of at least 2 seconds with exponential - * backoff retry to poll the operation result. The metadata contains the request to help callers - * to map responses to requests. + * backoff retry to poll the operation result. The metadata contains the metadata for the + * long-running operation. * *

    Sample code: * @@ -1360,7 +1372,7 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * .setAnalysisQuery(IamPolicyAnalysisQuery.newBuilder().build()) * .setOutputConfig(IamPolicyAnalysisOutputConfig.newBuilder().build()) * .build(); - * OperationFuture + * OperationFuture * future = * assetServiceClient.analyzeIamPolicyLongrunningOperationCallable().futureCall(request); * // Do something. @@ -1371,7 +1383,7 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r public final OperationCallable< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationCallable() { return stub.analyzeIamPolicyLongrunningOperationCallable(); } @@ -1384,8 +1396,8 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * [AnalyzeIamPolicyResponse][google.cloud.asset.v1.AnalyzeIamPolicyResponse]. This method * implements the [google.longrunning.Operation][google.longrunning.Operation], which allows you * to track the operation status. We recommend intervals of at least 2 seconds with exponential - * backoff retry to poll the operation result. The metadata contains the request to help callers - * to map responses to requests. + * backoff retry to poll the operation result. The metadata contains the metadata for the + * long-running operation. * *

    Sample code: * @@ -1408,6 +1420,60 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r return stub.analyzeIamPolicyLongrunningCallable(); } + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Analyze moving a resource to a specified destination without kicking off the actual move. The + * analysis is best effort depending on the user's permissions of viewing different hierarchical + * policies and configurations. The policies and configuration are subject to change before the + * actual resource migration takes place. + * + *

    Sample code: + * + *

    {@code
    +   * try (AssetServiceClient assetServiceClient = AssetServiceClient.create()) {
    +   *   AnalyzeMoveRequest request =
    +   *       AnalyzeMoveRequest.newBuilder()
    +   *           .setResource("resource-341064690")
    +   *           .setDestinationParent("destinationParent-1733659048")
    +   *           .build();
    +   *   AnalyzeMoveResponse response = assetServiceClient.analyzeMove(request);
    +   * }
    +   * }
    + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final AnalyzeMoveResponse analyzeMove(AnalyzeMoveRequest request) { + return analyzeMoveCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Analyze moving a resource to a specified destination without kicking off the actual move. The + * analysis is best effort depending on the user's permissions of viewing different hierarchical + * policies and configurations. The policies and configuration are subject to change before the + * actual resource migration takes place. + * + *

    Sample code: + * + *

    {@code
    +   * try (AssetServiceClient assetServiceClient = AssetServiceClient.create()) {
    +   *   AnalyzeMoveRequest request =
    +   *       AnalyzeMoveRequest.newBuilder()
    +   *           .setResource("resource-341064690")
    +   *           .setDestinationParent("destinationParent-1733659048")
    +   *           .build();
    +   *   ApiFuture future =
    +   *       assetServiceClient.analyzeMoveCallable().futureCall(request);
    +   *   // Do something.
    +   *   AnalyzeMoveResponse response = future.get();
    +   * }
    +   * }
    + */ + public final UnaryCallable analyzeMoveCallable() { + return stub.analyzeMoveCallable(); + } + @Override public final void close() { stub.close(); diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClientTest.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClientTest.java index de8ca67414..41f50cea3a 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClientTest.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClientTest.java @@ -113,6 +113,7 @@ public void exportAssetsTest() throws Exception { .addAllAssetTypes(new ArrayList()) .setContentType(ContentType.forNumber(0)) .setOutputConfig(OutputConfig.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); ExportAssetsResponse actualResponse = client.exportAssetsAsync(request).get(); @@ -127,6 +128,8 @@ public void exportAssetsTest() throws Exception { Assert.assertEquals(request.getAssetTypesList(), actualRequest.getAssetTypesList()); Assert.assertEquals(request.getContentType(), actualRequest.getContentType()); Assert.assertEquals(request.getOutputConfig(), actualRequest.getOutputConfig()); + Assert.assertEquals( + request.getRelationshipTypesList(), actualRequest.getRelationshipTypesList()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -146,6 +149,7 @@ public void exportAssetsExceptionTest() throws Exception { .addAllAssetTypes(new ArrayList()) .setContentType(ContentType.forNumber(0)) .setOutputConfig(OutputConfig.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); client.exportAssetsAsync(request).get(); Assert.fail("No exception raised"); @@ -258,6 +262,7 @@ public void batchGetAssetsHistoryTest() throws Exception { .addAllAssetNames(new ArrayList()) .setContentType(ContentType.forNumber(0)) .setReadTimeWindow(TimeWindow.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); BatchGetAssetsHistoryResponse actualResponse = client.batchGetAssetsHistory(request); @@ -272,6 +277,8 @@ public void batchGetAssetsHistoryTest() throws Exception { Assert.assertEquals(request.getAssetNamesList(), actualRequest.getAssetNamesList()); Assert.assertEquals(request.getContentType(), actualRequest.getContentType()); Assert.assertEquals(request.getReadTimeWindow(), actualRequest.getReadTimeWindow()); + Assert.assertEquals( + request.getRelationshipTypesList(), actualRequest.getRelationshipTypesList()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -290,6 +297,7 @@ public void batchGetAssetsHistoryExceptionTest() throws Exception { .addAllAssetNames(new ArrayList()) .setContentType(ContentType.forNumber(0)) .setReadTimeWindow(TimeWindow.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); client.batchGetAssetsHistory(request); Assert.fail("No exception raised"); @@ -308,6 +316,7 @@ public void createFeedTest() throws Exception { .setContentType(ContentType.forNumber(0)) .setFeedOutputConfig(FeedOutputConfig.newBuilder().build()) .setCondition(Expr.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); mockAssetService.addResponse(expectedResponse); @@ -351,6 +360,7 @@ public void getFeedTest() throws Exception { .setContentType(ContentType.forNumber(0)) .setFeedOutputConfig(FeedOutputConfig.newBuilder().build()) .setCondition(Expr.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); mockAssetService.addResponse(expectedResponse); @@ -394,6 +404,7 @@ public void getFeedTest2() throws Exception { .setContentType(ContentType.forNumber(0)) .setFeedOutputConfig(FeedOutputConfig.newBuilder().build()) .setCondition(Expr.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); mockAssetService.addResponse(expectedResponse); @@ -473,6 +484,7 @@ public void updateFeedTest() throws Exception { .setContentType(ContentType.forNumber(0)) .setFeedOutputConfig(FeedOutputConfig.newBuilder().build()) .setCondition(Expr.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); mockAssetService.addResponse(expectedResponse); @@ -777,4 +789,50 @@ public void analyzeIamPolicyLongrunningExceptionTest() throws Exception { Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); } } + + @Test + public void analyzeMoveTest() throws Exception { + AnalyzeMoveResponse expectedResponse = + AnalyzeMoveResponse.newBuilder().addAllMoveAnalysis(new ArrayList()).build(); + mockAssetService.addResponse(expectedResponse); + + AnalyzeMoveRequest request = + AnalyzeMoveRequest.newBuilder() + .setResource("resource-341064690") + .setDestinationParent("destinationParent-1733659048") + .build(); + + AnalyzeMoveResponse actualResponse = client.analyzeMove(request); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockAssetService.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + AnalyzeMoveRequest actualRequest = ((AnalyzeMoveRequest) actualRequests.get(0)); + + Assert.assertEquals(request.getResource(), actualRequest.getResource()); + Assert.assertEquals(request.getDestinationParent(), actualRequest.getDestinationParent()); + Assert.assertEquals(request.getView(), actualRequest.getView()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void analyzeMoveExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockAssetService.addException(exception); + + try { + AnalyzeMoveRequest request = + AnalyzeMoveRequest.newBuilder() + .setResource("resource-341064690") + .setDestinationParent("destinationParent-1733659048") + .build(); + client.analyzeMove(request); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } } diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceSettings.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceSettings.java index df338c00a9..8bca7d5631 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceSettings.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceSettings.java @@ -154,12 +154,17 @@ public UnaryCallSettings deleteFeedSettings() { public OperationCallSettings< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings() { return ((AssetServiceStubSettings) getStubSettings()) .analyzeIamPolicyLongrunningOperationSettings(); } + /** Returns the object with the settings used for calls to analyzeMove. */ + public UnaryCallSettings analyzeMoveSettings() { + return ((AssetServiceStubSettings) getStubSettings()).analyzeMoveSettings(); + } + public static final AssetServiceSettings create(AssetServiceStubSettings stub) throws IOException { return new AssetServiceSettings.Builder(stub.toBuilder()).build(); @@ -338,11 +343,17 @@ public UnaryCallSettings.Builder deleteFeedSettings() public OperationCallSettings.Builder< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings() { return getStubSettingsBuilder().analyzeIamPolicyLongrunningOperationSettings(); } + /** Returns the builder for the settings used for calls to analyzeMove. */ + public UnaryCallSettings.Builder + analyzeMoveSettings() { + return getStubSettingsBuilder().analyzeMoveSettings(); + } + @Override public AssetServiceSettings build() throws IOException { return new AssetServiceSettings(this); diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/MockAssetServiceImpl.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/MockAssetServiceImpl.java index 643691d8d4..f72ed1eaa6 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/MockAssetServiceImpl.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/MockAssetServiceImpl.java @@ -310,4 +310,25 @@ public void analyzeIamPolicyLongrunning( Exception.class.getName()))); } } + + @Override + public void analyzeMove( + AnalyzeMoveRequest request, StreamObserver responseObserver) { + Object response = responses.poll(); + if (response instanceof AnalyzeMoveResponse) { + requests.add(request); + responseObserver.onNext(((AnalyzeMoveResponse) response)); + responseObserver.onCompleted(); + } else if (response instanceof Exception) { + responseObserver.onError(((Exception) response)); + } else { + responseObserver.onError( + new IllegalArgumentException( + String.format( + "Unrecognized response type %s for method AnalyzeMove, expected %s or %s", + response == null ? "null" : response.getClass().getName(), + AnalyzeMoveResponse.class.getName(), + Exception.class.getName()))); + } + } } diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/gapic_metadata.json b/test/integration/goldens/asset/com/google/cloud/asset/v1/gapic_metadata.json index ea1187e7ac..05ba5ae5ea 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/gapic_metadata.json +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/gapic_metadata.json @@ -16,6 +16,9 @@ "AnalyzeIamPolicyLongrunning": { "methods": ["analyzeIamPolicyLongrunningAsync", "analyzeIamPolicyLongrunningOperationCallable", "analyzeIamPolicyLongrunningCallable"] }, + "AnalyzeMove": { + "methods": ["analyzeMove", "analyzeMoveCallable"] + }, "BatchGetAssetsHistory": { "methods": ["batchGetAssetsHistory", "batchGetAssetsHistoryCallable"] }, diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/package-info.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/package-info.java index 27db247ed3..d07bbc1fb7 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/package-info.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/package-info.java @@ -31,6 +31,7 @@ * .addAllAssetNames(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setReadTimeWindow(TimeWindow.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * BatchGetAssetsHistoryResponse response = assetServiceClient.batchGetAssetsHistory(request); * } diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStub.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStub.java index 462d7e2922..f3b324ba29 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStub.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStub.java @@ -23,10 +23,13 @@ import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.UnaryCallable; +import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningMetadata; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningResponse; import com.google.cloud.asset.v1.AnalyzeIamPolicyRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyResponse; +import com.google.cloud.asset.v1.AnalyzeMoveRequest; +import com.google.cloud.asset.v1.AnalyzeMoveResponse; import com.google.cloud.asset.v1.BatchGetAssetsHistoryRequest; import com.google.cloud.asset.v1.BatchGetAssetsHistoryResponse; import com.google.cloud.asset.v1.CreateFeedRequest; @@ -132,7 +135,7 @@ public UnaryCallable deleteFeedCallable() { public OperationCallable< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationCallable() { throw new UnsupportedOperationException( "Not implemented: analyzeIamPolicyLongrunningOperationCallable()"); @@ -144,6 +147,10 @@ public UnaryCallable deleteFeedCallable() { "Not implemented: analyzeIamPolicyLongrunningCallable()"); } + public UnaryCallable analyzeMoveCallable() { + throw new UnsupportedOperationException("Not implemented: analyzeMoveCallable()"); + } + @Override public abstract void close(); } diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStubSettings.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStubSettings.java index 24b8b894a1..30012d98c6 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStubSettings.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStubSettings.java @@ -46,10 +46,13 @@ import com.google.api.gax.rpc.TransportChannelProvider; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; +import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningMetadata; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningResponse; import com.google.cloud.asset.v1.AnalyzeIamPolicyRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyResponse; +import com.google.cloud.asset.v1.AnalyzeMoveRequest; +import com.google.cloud.asset.v1.AnalyzeMoveResponse; import com.google.cloud.asset.v1.Asset; import com.google.cloud.asset.v1.BatchGetAssetsHistoryRequest; import com.google.cloud.asset.v1.BatchGetAssetsHistoryResponse; @@ -147,8 +150,9 @@ public class AssetServiceStubSettings extends StubSettings + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings; + private final UnaryCallSettings analyzeMoveSettings; private static final PagedListDescriptor LIST_ASSETS_PAGE_STR_DESC = @@ -413,11 +417,16 @@ public UnaryCallSettings deleteFeedSettings() { public OperationCallSettings< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings() { return analyzeIamPolicyLongrunningOperationSettings; } + /** Returns the object with the settings used for calls to analyzeMove. */ + public UnaryCallSettings analyzeMoveSettings() { + return analyzeMoveSettings; + } + @BetaApi("A restructuring of stub classes is planned, so this may break in the future") public AssetServiceStub createStub() throws IOException { if (getTransportChannelProvider() @@ -510,6 +519,7 @@ protected AssetServiceStubSettings(Builder settingsBuilder) throws IOException { settingsBuilder.analyzeIamPolicyLongrunningSettings().build(); analyzeIamPolicyLongrunningOperationSettings = settingsBuilder.analyzeIamPolicyLongrunningOperationSettings().build(); + analyzeMoveSettings = settingsBuilder.analyzeMoveSettings().build(); } /** Builder for AssetServiceStubSettings. */ @@ -545,8 +555,10 @@ public static class Builder extends StubSettings.Builder + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings; + private final UnaryCallSettings.Builder + analyzeMoveSettings; private static final ImmutableMap> RETRYABLE_CODE_DEFINITIONS; @@ -566,6 +578,7 @@ public static class Builder extends StubSettings.BuildernewArrayList(StatusCode.Code.UNAVAILABLE))); + definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList())); RETRYABLE_CODE_DEFINITIONS = definitions.build(); } @@ -615,6 +628,8 @@ public static class Builder extends StubSettings.Builder>of( @@ -654,7 +670,8 @@ protected Builder(ClientContext clientContext) { searchAllResourcesSettings, searchAllIamPoliciesSettings, analyzeIamPolicySettings, - analyzeIamPolicyLongrunningSettings); + analyzeIamPolicyLongrunningSettings, + analyzeMoveSettings); initDefaults(this); } @@ -677,6 +694,7 @@ protected Builder(AssetServiceStubSettings settings) { settings.analyzeIamPolicyLongrunningSettings.toBuilder(); analyzeIamPolicyLongrunningOperationSettings = settings.analyzeIamPolicyLongrunningOperationSettings.toBuilder(); + analyzeMoveSettings = settings.analyzeMoveSettings.toBuilder(); unaryMethodSettingsBuilders = ImmutableList.>of( @@ -691,7 +709,8 @@ protected Builder(AssetServiceStubSettings settings) { searchAllResourcesSettings, searchAllIamPoliciesSettings, analyzeIamPolicySettings, - analyzeIamPolicyLongrunningSettings); + analyzeIamPolicyLongrunningSettings, + analyzeMoveSettings); } private static Builder createDefault() { @@ -768,6 +787,11 @@ private static Builder initDefaults(Builder builder) { .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); + builder + .analyzeMoveSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); + builder .exportAssetsOperationSettings() .setInitialCallSettings( @@ -806,7 +830,7 @@ private static Builder initDefaults(Builder builder) { AnalyzeIamPolicyLongrunningResponse.class)) .setMetadataTransformer( ProtoOperationTransformers.MetadataTransformer.create( - AnalyzeIamPolicyLongrunningRequest.class)) + AnalyzeIamPolicyLongrunningMetadata.class)) .setPollingAlgorithm( OperationTimedPollAlgorithm.create( RetrySettings.newBuilder() @@ -922,11 +946,17 @@ public UnaryCallSettings.Builder deleteFeedSettings() public OperationCallSettings.Builder< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings() { return analyzeIamPolicyLongrunningOperationSettings; } + /** Returns the builder for the settings used for calls to analyzeMove. */ + public UnaryCallSettings.Builder + analyzeMoveSettings() { + return analyzeMoveSettings; + } + @Override public AssetServiceStubSettings build() throws IOException { return new AssetServiceStubSettings(this); diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java index d884f02bf9..d467435938 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java @@ -27,10 +27,13 @@ import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.UnaryCallable; +import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningMetadata; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningResponse; import com.google.cloud.asset.v1.AnalyzeIamPolicyRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyResponse; +import com.google.cloud.asset.v1.AnalyzeMoveRequest; +import com.google.cloud.asset.v1.AnalyzeMoveResponse; import com.google.cloud.asset.v1.BatchGetAssetsHistoryRequest; import com.google.cloud.asset.v1.BatchGetAssetsHistoryResponse; import com.google.cloud.asset.v1.CreateFeedRequest; @@ -180,6 +183,16 @@ public class GrpcAssetServiceStub extends AssetServiceStub { .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) .build(); + private static final MethodDescriptor + analyzeMoveMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.cloud.asset.v1.AssetService/AnalyzeMove") + .setRequestMarshaller(ProtoUtils.marshaller(AnalyzeMoveRequest.getDefaultInstance())) + .setResponseMarshaller( + ProtoUtils.marshaller(AnalyzeMoveResponse.getDefaultInstance())) + .build(); + private final UnaryCallable exportAssetsCallable; private final OperationCallable exportAssetsOperationCallable; @@ -207,8 +220,9 @@ public class GrpcAssetServiceStub extends AssetServiceStub { private final OperationCallable< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationCallable; + private final UnaryCallable analyzeMoveCallable; private final BackgroundResource backgroundResources; private final GrpcOperationsStub operationsStub; @@ -382,6 +396,16 @@ protected GrpcAssetServiceStub( return params.build(); }) .build(); + GrpcCallSettings analyzeMoveTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(analyzeMoveMethodDescriptor) + .setParamsExtractor( + request -> { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("resource", String.valueOf(request.getResource())); + return params.build(); + }) + .build(); this.exportAssetsCallable = callableFactory.createUnaryCallable( @@ -452,6 +476,9 @@ protected GrpcAssetServiceStub( settings.analyzeIamPolicyLongrunningOperationSettings(), clientContext, operationsStub); + this.analyzeMoveCallable = + callableFactory.createUnaryCallable( + analyzeMoveTransportSettings, settings.analyzeMoveSettings(), clientContext); this.backgroundResources = new BackgroundResourceAggregation(clientContext.getBackgroundResources()); @@ -553,11 +580,16 @@ public UnaryCallable deleteFeedCallable() { public OperationCallable< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationCallable() { return analyzeIamPolicyLongrunningOperationCallable; } + @Override + public UnaryCallable analyzeMoveCallable() { + return analyzeMoveCallable; + } + @Override public final void close() { try { diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java index eb9db7ce24..f9039b41df 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java @@ -20,9 +20,11 @@ import com.google.api.core.ApiFutures; import com.google.api.core.BetaApi; import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.paging.AbstractFixedSizeCollection; import com.google.api.gax.paging.AbstractPage; import com.google.api.gax.paging.AbstractPagedListResponse; +import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.PageContext; import com.google.api.gax.rpc.UnaryCallable; import com.google.cloud.compute.v1.stub.AddressesStub; @@ -46,9 +48,10 @@ *
    {@code
      * try (AddressesClient addressesClient = AddressesClient.create()) {
      *   String project = "project-309310695";
    - *   String region = "region-934795532";
    - *   String address = "address-1147692044";
    - *   Operation response = addressesClient.delete(project, region, address);
    + *   for (Map.Entry element :
    + *       addressesClient.aggregatedList(project).iterateAll()) {
    + *     // doThingsWith(element);
    + *   }
      * }
      * }
    * @@ -284,7 +287,7 @@ public final AggregatedListPagedResponse aggregatedList(AggregatedListAddressesR * String project = "project-309310695"; * String region = "region-934795532"; * String address = "address-1147692044"; - * Operation response = addressesClient.delete(project, region, address); + * Operation response = addressesClient.deleteAsync(project, region, address).get(); * } * } * @@ -293,14 +296,15 @@ public final AggregatedListPagedResponse aggregatedList(AggregatedListAddressesR * @param address Name of the address resource to delete. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final Operation delete(String project, String region, String address) { + public final OperationFuture deleteAsync( + String project, String region, String address) { DeleteAddressRequest request = DeleteAddressRequest.newBuilder() .setProject(project) .setRegion(region) .setAddress(address) .build(); - return delete(request); + return deleteAsync(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD. @@ -318,15 +322,44 @@ public final Operation delete(String project, String region, String address) { * .setRegion("region-934795532") * .setRequestId("requestId693933066") * .build(); - * Operation response = addressesClient.delete(request); + * Operation response = addressesClient.deleteAsync(request).get(); * } * } * * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final Operation delete(DeleteAddressRequest request) { - return deleteCallable().call(request); + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture deleteAsync(DeleteAddressRequest request) { + return deleteOperationCallable().futureCall(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Deletes the specified address resource. + * + *

    Sample code: + * + *

    {@code
    +   * try (AddressesClient addressesClient = AddressesClient.create()) {
    +   *   DeleteAddressRequest request =
    +   *       DeleteAddressRequest.newBuilder()
    +   *           .setAddress("address-1147692044")
    +   *           .setProject("project-309310695")
    +   *           .setRegion("region-934795532")
    +   *           .setRequestId("requestId693933066")
    +   *           .build();
    +   *   OperationFuture future =
    +   *       addressesClient.deleteOperationCallable().futureCall(request);
    +   *   // Do something.
    +   *   Operation response = future.get();
    +   * }
    +   * }
    + */ + public final OperationCallable + deleteOperationCallable() { + return stub.deleteOperationCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD. @@ -365,7 +398,7 @@ public final UnaryCallable deleteCallable() { * String project = "project-309310695"; * String region = "region-934795532"; * Address addressResource = Address.newBuilder().build(); - * Operation response = addressesClient.insert(project, region, addressResource); + * Operation response = addressesClient.insertAsync(project, region, addressResource).get(); * } * } * @@ -374,14 +407,15 @@ public final UnaryCallable deleteCallable() { * @param addressResource The body resource for this request * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final Operation insert(String project, String region, Address addressResource) { + public final OperationFuture insertAsync( + String project, String region, Address addressResource) { InsertAddressRequest request = InsertAddressRequest.newBuilder() .setProject(project) .setRegion(region) .setAddressResource(addressResource) .build(); - return insert(request); + return insertAsync(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD. @@ -399,15 +433,44 @@ public final Operation insert(String project, String region, Address addressReso * .setRegion("region-934795532") * .setRequestId("requestId693933066") * .build(); - * Operation response = addressesClient.insert(request); + * Operation response = addressesClient.insertAsync(request).get(); * } * } * * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final Operation insert(InsertAddressRequest request) { - return insertCallable().call(request); + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture insertAsync(InsertAddressRequest request) { + return insertOperationCallable().futureCall(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Creates an address resource in the specified project by using the data included in the request. + * + *

    Sample code: + * + *

    {@code
    +   * try (AddressesClient addressesClient = AddressesClient.create()) {
    +   *   InsertAddressRequest request =
    +   *       InsertAddressRequest.newBuilder()
    +   *           .setAddressResource(Address.newBuilder().build())
    +   *           .setProject("project-309310695")
    +   *           .setRegion("region-934795532")
    +   *           .setRequestId("requestId693933066")
    +   *           .build();
    +   *   OperationFuture future =
    +   *       addressesClient.insertOperationCallable().futureCall(request);
    +   *   // Do something.
    +   *   Operation response = future.get();
    +   * }
    +   * }
    + */ + public final OperationCallable + insertOperationCallable() { + return stub.insertOperationCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD. diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java index bc7d9c2a16..ec3f75047c 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java @@ -28,6 +28,7 @@ import com.google.api.gax.rpc.InvalidArgumentException; import com.google.api.gax.rpc.StatusCode; import com.google.api.gax.rpc.testing.FakeStatusCode; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.stub.HttpJsonAddressesStub; import com.google.common.collect.Lists; import java.io.IOException; @@ -36,6 +37,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; import javax.annotation.Generated; import org.junit.After; import org.junit.AfterClass; @@ -140,8 +142,8 @@ public void deleteTest() throws Exception { .setEndTime("endTime-1607243192") .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") - .setHttpErrorStatusCode(1386087020) - .setId("id3355") + .setHttpErrorStatusCode(0) + .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") .setName("name3373707") @@ -150,8 +152,9 @@ public void deleteTest() throws Exception { .setRegion("region-934795532") .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") + .setStatus(Status.DONE) .setStatusMessage("statusMessage-958704715") - .setTargetId("targetId-441951604") + .setTargetId(-815576439) .setTargetLink("targetLink486368555") .setUser("user3599307") .addAllWarnings(new ArrayList()) @@ -163,7 +166,7 @@ public void deleteTest() throws Exception { String region = "region-934795532"; String address = "address-1147692044"; - Operation actualResponse = client.delete(project, region, address); + Operation actualResponse = client.deleteAsync(project, region, address).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockService.getRequestPaths(); @@ -192,10 +195,9 @@ public void deleteExceptionTest() throws Exception { String project = "project-309310695"; String region = "region-934795532"; String address = "address-1147692044"; - client.delete(project, region, address); + client.deleteAsync(project, region, address).get(); Assert.fail("No exception raised"); - } catch (InvalidArgumentException e) { - // Expected exception. + } catch (ExecutionException e) { } } @@ -209,8 +211,8 @@ public void insertTest() throws Exception { .setEndTime("endTime-1607243192") .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") - .setHttpErrorStatusCode(1386087020) - .setId("id3355") + .setHttpErrorStatusCode(0) + .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") .setName("name3373707") @@ -219,8 +221,9 @@ public void insertTest() throws Exception { .setRegion("region-934795532") .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") + .setStatus(Status.DONE) .setStatusMessage("statusMessage-958704715") - .setTargetId("targetId-441951604") + .setTargetId(-815576439) .setTargetLink("targetLink486368555") .setUser("user3599307") .addAllWarnings(new ArrayList()) @@ -232,7 +235,7 @@ public void insertTest() throws Exception { String region = "region-934795532"; Address addressResource = Address.newBuilder().build(); - Operation actualResponse = client.insert(project, region, addressResource); + Operation actualResponse = client.insertAsync(project, region, addressResource).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockService.getRequestPaths(); @@ -261,10 +264,9 @@ public void insertExceptionTest() throws Exception { String project = "project-309310695"; String region = "region-934795532"; Address addressResource = Address.newBuilder().build(); - client.insert(project, region, addressResource); + client.insertAsync(project, region, addressResource).get(); Assert.fail("No exception raised"); - } catch (InvalidArgumentException e) { - // Expected exception. + } catch (ExecutionException e) { } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesSettings.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesSettings.java index d2dc359f73..58fbc804d6 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesSettings.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesSettings.java @@ -27,6 +27,7 @@ import com.google.api.gax.rpc.ApiClientHeaderProvider; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.ClientSettings; +import com.google.api.gax.rpc.OperationCallSettings; import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.StubSettings; import com.google.api.gax.rpc.TransportChannelProvider; @@ -51,15 +52,15 @@ *

    The builder of this class is recursive, so contained classes are themselves builders. When * build() is called, the tree of builders is called to create the complete settings object. * - *

    For example, to set the total timeout of delete to 30 seconds: + *

    For example, to set the total timeout of aggregatedList to 30 seconds: * *

    {@code
      * AddressesSettings.Builder addressesSettingsBuilder = AddressesSettings.newBuilder();
      * addressesSettingsBuilder
    - *     .deleteSettings()
    + *     .aggregatedListSettings()
      *     .setRetrySettings(
      *         addressesSettingsBuilder
    - *             .deleteSettings()
    + *             .aggregatedListSettings()
      *             .getRetrySettings()
      *             .toBuilder()
      *             .setTotalTimeout(Duration.ofSeconds(30))
    @@ -82,11 +83,23 @@ public UnaryCallSettings deleteSettings() {
         return ((AddressesStubSettings) getStubSettings()).deleteSettings();
       }
     
    +  /** Returns the object with the settings used for calls to delete. */
    +  public OperationCallSettings
    +      deleteOperationSettings() {
    +    return ((AddressesStubSettings) getStubSettings()).deleteOperationSettings();
    +  }
    +
       /** Returns the object with the settings used for calls to insert. */
       public UnaryCallSettings insertSettings() {
         return ((AddressesStubSettings) getStubSettings()).insertSettings();
       }
     
    +  /** Returns the object with the settings used for calls to insert. */
    +  public OperationCallSettings
    +      insertOperationSettings() {
    +    return ((AddressesStubSettings) getStubSettings()).insertOperationSettings();
    +  }
    +
       /** Returns the object with the settings used for calls to list. */
       public PagedCallSettings listSettings() {
         return ((AddressesStubSettings) getStubSettings()).listSettings();
    @@ -201,11 +214,23 @@ public UnaryCallSettings.Builder deleteSettings
           return getStubSettingsBuilder().deleteSettings();
         }
     
    +    /** Returns the builder for the settings used for calls to delete. */
    +    public OperationCallSettings.Builder
    +        deleteOperationSettings() {
    +      return getStubSettingsBuilder().deleteOperationSettings();
    +    }
    +
         /** Returns the builder for the settings used for calls to insert. */
         public UnaryCallSettings.Builder insertSettings() {
           return getStubSettingsBuilder().insertSettings();
         }
     
    +    /** Returns the builder for the settings used for calls to insert. */
    +    public OperationCallSettings.Builder
    +        insertOperationSettings() {
    +      return getStubSettingsBuilder().insertOperationSettings();
    +    }
    +
         /** Returns the builder for the settings used for calls to list. */
         public PagedCallSettings.Builder
             listSettings() {
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClient.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClient.java
    index fb6a5e296d..09fb0b090a 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClient.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClient.java
    @@ -222,6 +222,112 @@ public final UnaryCallable getCallable() {
         return stub.getCallable();
       }
     
    +  // AUTO-GENERATED DOCUMENTATION AND METHOD.
    +  /**
    +   * Waits for the specified Operation resource to return as `DONE` or for the request to approach
    +   * the 2 minute deadline, and retrieves the specified Operation resource. This method differs from
    +   * the `GET` method in that it waits for no more than the default deadline (2 minutes) and then
    +   * returns the current state of the operation, which might be `DONE` or still in progress.
    +   *
    +   * 

    This method is called on a best-effort basis. Specifically: - In uncommon cases, when the + * server is overloaded, the request might return before the default deadline is reached, or might + * return after zero seconds. - If the default deadline is reached, there is no guarantee that the + * operation is actually done when the method returns. Be prepared to retry if the operation is + * not `DONE`. + * + *

    Sample code: + * + *

    {@code
    +   * try (RegionOperationsClient regionOperationsClient = RegionOperationsClient.create()) {
    +   *   String project = "project-309310695";
    +   *   String region = "region-934795532";
    +   *   String operation = "operation1662702951";
    +   *   Operation response = regionOperationsClient.wait(project, region, operation);
    +   * }
    +   * }
    + * + * @param project Project ID for this request. + * @param region Name of the region for this request. + * @param operation Name of the Operations resource to return. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Operation wait(String project, String region, String operation) { + WaitRegionOperationRequest request = + WaitRegionOperationRequest.newBuilder() + .setProject(project) + .setRegion(region) + .setOperation(operation) + .build(); + return wait(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Waits for the specified Operation resource to return as `DONE` or for the request to approach + * the 2 minute deadline, and retrieves the specified Operation resource. This method differs from + * the `GET` method in that it waits for no more than the default deadline (2 minutes) and then + * returns the current state of the operation, which might be `DONE` or still in progress. + * + *

    This method is called on a best-effort basis. Specifically: - In uncommon cases, when the + * server is overloaded, the request might return before the default deadline is reached, or might + * return after zero seconds. - If the default deadline is reached, there is no guarantee that the + * operation is actually done when the method returns. Be prepared to retry if the operation is + * not `DONE`. + * + *

    Sample code: + * + *

    {@code
    +   * try (RegionOperationsClient regionOperationsClient = RegionOperationsClient.create()) {
    +   *   WaitRegionOperationRequest request =
    +   *       WaitRegionOperationRequest.newBuilder()
    +   *           .setOperation("operation1662702951")
    +   *           .setProject("project-309310695")
    +   *           .setRegion("region-934795532")
    +   *           .build();
    +   *   Operation response = regionOperationsClient.wait(request);
    +   * }
    +   * }
    + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Operation wait(WaitRegionOperationRequest request) { + return waitCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Waits for the specified Operation resource to return as `DONE` or for the request to approach + * the 2 minute deadline, and retrieves the specified Operation resource. This method differs from + * the `GET` method in that it waits for no more than the default deadline (2 minutes) and then + * returns the current state of the operation, which might be `DONE` or still in progress. + * + *

    This method is called on a best-effort basis. Specifically: - In uncommon cases, when the + * server is overloaded, the request might return before the default deadline is reached, or might + * return after zero seconds. - If the default deadline is reached, there is no guarantee that the + * operation is actually done when the method returns. Be prepared to retry if the operation is + * not `DONE`. + * + *

    Sample code: + * + *

    {@code
    +   * try (RegionOperationsClient regionOperationsClient = RegionOperationsClient.create()) {
    +   *   WaitRegionOperationRequest request =
    +   *       WaitRegionOperationRequest.newBuilder()
    +   *           .setOperation("operation1662702951")
    +   *           .setProject("project-309310695")
    +   *           .setRegion("region-934795532")
    +   *           .build();
    +   *   ApiFuture future = regionOperationsClient.waitCallable().futureCall(request);
    +   *   // Do something.
    +   *   Operation response = future.get();
    +   * }
    +   * }
    + */ + public final UnaryCallable waitCallable() { + return stub.waitCallable(); + } + @Override public final void close() { stub.close(); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java index 7f6b78232a..c1a2c78519 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java @@ -25,6 +25,7 @@ import com.google.api.gax.rpc.InvalidArgumentException; import com.google.api.gax.rpc.StatusCode; import com.google.api.gax.rpc.testing.FakeStatusCode; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.stub.HttpJsonRegionOperationsStub; import java.io.IOException; import java.util.ArrayList; @@ -82,8 +83,8 @@ public void getTest() throws Exception { .setEndTime("endTime-1607243192") .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") - .setHttpErrorStatusCode(1386087020) - .setId("id3355") + .setHttpErrorStatusCode(0) + .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") .setName("name3373707") @@ -92,8 +93,9 @@ public void getTest() throws Exception { .setRegion("region-934795532") .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") + .setStatus(Status.DONE) .setStatusMessage("statusMessage-958704715") - .setTargetId("targetId-441951604") + .setTargetId(-815576439) .setTargetLink("targetLink486368555") .setUser("user3599307") .addAllWarnings(new ArrayList()) @@ -140,4 +142,74 @@ public void getExceptionTest() throws Exception { // Expected exception. } } + + @Test + public void waitTest() throws Exception { + Operation expectedResponse = + Operation.newBuilder() + .setClientOperationId("clientOperationId-1230366697") + .setCreationTimestamp("creationTimestamp-370203401") + .setDescription("description-1724546052") + .setEndTime("endTime-1607243192") + .setError(Error.newBuilder().build()) + .setHttpErrorMessage("httpErrorMessage1577303431") + .setHttpErrorStatusCode(0) + .setId(3355) + .setInsertTime("insertTime966165798") + .setKind("kind3292052") + .setName("name3373707") + .setOperationType("operationType91999553") + .setProgress(-1001078227) + .setRegion("region-934795532") + .setSelfLink("selfLink1191800166") + .setStartTime("startTime-2129294769") + .setStatus(Status.DONE) + .setStatusMessage("statusMessage-958704715") + .setTargetId(-815576439) + .setTargetLink("targetLink486368555") + .setUser("user3599307") + .addAllWarnings(new ArrayList()) + .setZone("zone3744684") + .build(); + mockService.addResponse(expectedResponse); + + String project = "project-309310695"; + String region = "region-934795532"; + String operation = "operation1662702951"; + + Operation actualResponse = client.wait(project, region, operation); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockService.getRequestPaths(); + Assert.assertEquals(1, actualRequests.size()); + + String apiClientHeaderKey = + mockService + .getRequestHeaders() + .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey()) + .iterator() + .next(); + Assert.assertTrue( + GaxHttpJsonProperties.getDefaultApiClientHeaderPattern() + .matcher(apiClientHeaderKey) + .matches()); + } + + @Test + public void waitExceptionTest() throws Exception { + ApiException exception = + ApiExceptionFactory.createException( + new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false); + mockService.addException(exception); + + try { + String project = "project-309310695"; + String region = "region-934795532"; + String operation = "operation1662702951"; + client.wait(project, region, operation); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsSettings.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsSettings.java index 4e0ffca9d4..91cabed69d 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsSettings.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsSettings.java @@ -72,6 +72,11 @@ public UnaryCallSettings getSettings() { return ((RegionOperationsStubSettings) getStubSettings()).getSettings(); } + /** Returns the object with the settings used for calls to wait. */ + public UnaryCallSettings waitSettings() { + return ((RegionOperationsStubSettings) getStubSettings()).waitSettings(); + } + public static final RegionOperationsSettings create(RegionOperationsStubSettings stub) throws IOException { return new RegionOperationsSettings.Builder(stub.toBuilder()).build(); @@ -175,6 +180,11 @@ public UnaryCallSettings.Builder getSettin return getStubSettingsBuilder().getSettings(); } + /** Returns the builder for the settings used for calls to wait. */ + public UnaryCallSettings.Builder waitSettings() { + return getStubSettingsBuilder().waitSettings(); + } + @Override public RegionOperationsSettings build() throws IOException { return new RegionOperationsSettings(this); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json b/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json index 14eb0320fd..a56d0a2382 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json @@ -14,10 +14,10 @@ "methods": ["aggregatedList", "aggregatedList", "aggregatedListPagedCallable", "aggregatedListCallable"] }, "Delete": { - "methods": ["delete", "delete", "deleteCallable"] + "methods": ["deleteAsync", "deleteAsync", "deleteOperationCallable", "deleteCallable"] }, "Insert": { - "methods": ["insert", "insert", "insertCallable"] + "methods": ["insertAsync", "insertAsync", "insertOperationCallable", "insertCallable"] }, "List": { "methods": ["list", "list", "listPagedCallable", "listCallable"] @@ -33,6 +33,9 @@ "rpcs": { "Get": { "methods": ["get", "get", "getCallable"] + }, + "Wait": { + "methods": ["wait", "wait", "waitCallable"] } } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/package-info.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/package-info.java index 941f3ab751..e525d9c7df 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/package-info.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/package-info.java @@ -28,9 +28,10 @@ *
    {@code
      * try (AddressesClient addressesClient = AddressesClient.create()) {
      *   String project = "project-309310695";
    - *   String region = "region-934795532";
    - *   String address = "address-1147692044";
    - *   Operation response = addressesClient.delete(project, region, address);
    + *   for (Map.Entry element :
    + *       addressesClient.aggregatedList(project).iterateAll()) {
    + *     // doThingsWith(element);
    + *   }
      * }
      * }
    * diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java index b7d7f6e590..9ae394b7ca 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java @@ -20,6 +20,7 @@ import static com.google.cloud.compute.v1.AddressesClient.ListPagedResponse; import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.UnaryCallable; import com.google.cloud.compute.v1.AddressAggregatedList; import com.google.cloud.compute.v1.AddressList; @@ -49,10 +50,18 @@ public abstract class AddressesStub implements BackgroundResource { throw new UnsupportedOperationException("Not implemented: aggregatedListCallable()"); } + public OperationCallable deleteOperationCallable() { + throw new UnsupportedOperationException("Not implemented: deleteOperationCallable()"); + } + public UnaryCallable deleteCallable() { throw new UnsupportedOperationException("Not implemented: deleteCallable()"); } + public OperationCallable insertOperationCallable() { + throw new UnsupportedOperationException("Not implemented: insertOperationCallable()"); + } + public UnaryCallable insertCallable() { throw new UnsupportedOperationException("Not implemented: insertCallable()"); } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java index 38bfb441e7..b998276981 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java @@ -28,10 +28,14 @@ import com.google.api.gax.httpjson.GaxHttpJsonProperties; import com.google.api.gax.httpjson.HttpJsonTransportChannel; import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider; +import com.google.api.gax.httpjson.ProtoOperationTransformers; +import com.google.api.gax.longrunning.OperationSnapshot; +import com.google.api.gax.longrunning.OperationTimedPollAlgorithm; import com.google.api.gax.retrying.RetrySettings; import com.google.api.gax.rpc.ApiCallContext; import com.google.api.gax.rpc.ApiClientHeaderProvider; import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.rpc.OperationCallSettings; import com.google.api.gax.rpc.PageContext; import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.PagedListDescriptor; @@ -76,15 +80,15 @@ *

    The builder of this class is recursive, so contained classes are themselves builders. When * build() is called, the tree of builders is called to create the complete settings object. * - *

    For example, to set the total timeout of delete to 30 seconds: + *

    For example, to set the total timeout of aggregatedList to 30 seconds: * *

    {@code
      * AddressesStubSettings.Builder addressesSettingsBuilder = AddressesStubSettings.newBuilder();
      * addressesSettingsBuilder
    - *     .deleteSettings()
    + *     .aggregatedListSettings()
      *     .setRetrySettings(
      *         addressesSettingsBuilder
    - *             .deleteSettings()
    + *             .aggregatedListSettings()
      *             .getRetrySettings()
      *             .toBuilder()
      *             .setTotalTimeout(Duration.ofSeconds(30))
    @@ -105,7 +109,11 @@ public class AddressesStubSettings extends StubSettings {
               AggregatedListAddressesRequest, AddressAggregatedList, AggregatedListPagedResponse>
           aggregatedListSettings;
       private final UnaryCallSettings deleteSettings;
    +  private final OperationCallSettings
    +      deleteOperationSettings;
       private final UnaryCallSettings insertSettings;
    +  private final OperationCallSettings
    +      insertOperationSettings;
       private final PagedCallSettings
           listSettings;
     
    @@ -243,11 +251,23 @@ public UnaryCallSettings deleteSettings() {
         return deleteSettings;
       }
     
    +  /** Returns the object with the settings used for calls to delete. */
    +  public OperationCallSettings
    +      deleteOperationSettings() {
    +    return deleteOperationSettings;
    +  }
    +
       /** Returns the object with the settings used for calls to insert. */
       public UnaryCallSettings insertSettings() {
         return insertSettings;
       }
     
    +  /** Returns the object with the settings used for calls to insert. */
    +  public OperationCallSettings
    +      insertOperationSettings() {
    +    return insertOperationSettings;
    +  }
    +
       /** Returns the object with the settings used for calls to list. */
       public PagedCallSettings listSettings() {
         return listSettings;
    @@ -331,7 +351,9 @@ protected AddressesStubSettings(Builder settingsBuilder) throws IOException {
     
         aggregatedListSettings = settingsBuilder.aggregatedListSettings().build();
         deleteSettings = settingsBuilder.deleteSettings().build();
    +    deleteOperationSettings = settingsBuilder.deleteOperationSettings().build();
         insertSettings = settingsBuilder.insertSettings().build();
    +    insertOperationSettings = settingsBuilder.insertOperationSettings().build();
         listSettings = settingsBuilder.listSettings().build();
       }
     
    @@ -342,7 +364,11 @@ public static class Builder extends StubSettings.Builder
             aggregatedListSettings;
         private final UnaryCallSettings.Builder deleteSettings;
    +    private final OperationCallSettings.Builder
    +        deleteOperationSettings;
         private final UnaryCallSettings.Builder insertSettings;
    +    private final OperationCallSettings.Builder
    +        insertOperationSettings;
         private final PagedCallSettings.Builder
             listSettings;
         private static final ImmutableMap>
    @@ -397,7 +423,9 @@ protected Builder(ClientContext clientContext) {
     
           aggregatedListSettings = PagedCallSettings.newBuilder(AGGREGATED_LIST_PAGE_STR_FACT);
           deleteSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
    +      deleteOperationSettings = OperationCallSettings.newBuilder();
           insertSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
    +      insertOperationSettings = OperationCallSettings.newBuilder();
           listSettings = PagedCallSettings.newBuilder(LIST_PAGE_STR_FACT);
     
           unaryMethodSettingsBuilders =
    @@ -411,7 +439,9 @@ protected Builder(AddressesStubSettings settings) {
     
           aggregatedListSettings = settings.aggregatedListSettings.toBuilder();
           deleteSettings = settings.deleteSettings.toBuilder();
    +      deleteOperationSettings = settings.deleteOperationSettings.toBuilder();
           insertSettings = settings.insertSettings.toBuilder();
    +      insertOperationSettings = settings.insertOperationSettings.toBuilder();
           listSettings = settings.listSettings.toBuilder();
     
           unaryMethodSettingsBuilders =
    @@ -453,6 +483,54 @@ private static Builder initDefaults(Builder builder) {
               .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_0_codes"))
               .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_0_params"));
     
    +      builder
    +          .deleteOperationSettings()
    +          .setInitialCallSettings(
    +              UnaryCallSettings
    +                  .newUnaryCallSettingsBuilder()
    +                  .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes"))
    +                  .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params"))
    +                  .build())
    +          .setResponseTransformer(
    +              ProtoOperationTransformers.ResponseTransformer.create(Operation.class))
    +          .setMetadataTransformer(
    +              ProtoOperationTransformers.MetadataTransformer.create(Operation.class))
    +          .setPollingAlgorithm(
    +              OperationTimedPollAlgorithm.create(
    +                  RetrySettings.newBuilder()
    +                      .setInitialRetryDelay(Duration.ofMillis(5000L))
    +                      .setRetryDelayMultiplier(1.5)
    +                      .setMaxRetryDelay(Duration.ofMillis(45000L))
    +                      .setInitialRpcTimeout(Duration.ZERO)
    +                      .setRpcTimeoutMultiplier(1.0)
    +                      .setMaxRpcTimeout(Duration.ZERO)
    +                      .setTotalTimeout(Duration.ofMillis(300000L))
    +                      .build()));
    +
    +      builder
    +          .insertOperationSettings()
    +          .setInitialCallSettings(
    +              UnaryCallSettings
    +                  .newUnaryCallSettingsBuilder()
    +                  .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes"))
    +                  .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params"))
    +                  .build())
    +          .setResponseTransformer(
    +              ProtoOperationTransformers.ResponseTransformer.create(Operation.class))
    +          .setMetadataTransformer(
    +              ProtoOperationTransformers.MetadataTransformer.create(Operation.class))
    +          .setPollingAlgorithm(
    +              OperationTimedPollAlgorithm.create(
    +                  RetrySettings.newBuilder()
    +                      .setInitialRetryDelay(Duration.ofMillis(5000L))
    +                      .setRetryDelayMultiplier(1.5)
    +                      .setMaxRetryDelay(Duration.ofMillis(45000L))
    +                      .setInitialRpcTimeout(Duration.ZERO)
    +                      .setRpcTimeoutMultiplier(1.0)
    +                      .setMaxRpcTimeout(Duration.ZERO)
    +                      .setTotalTimeout(Duration.ofMillis(300000L))
    +                      .build()));
    +
           return builder;
         }
     
    @@ -483,11 +561,27 @@ public UnaryCallSettings.Builder deleteSettings
           return deleteSettings;
         }
     
    +    /** Returns the builder for the settings used for calls to delete. */
    +    @BetaApi(
    +        "The surface for use by generated code is not stable yet and may change in the future.")
    +    public OperationCallSettings.Builder
    +        deleteOperationSettings() {
    +      return deleteOperationSettings;
    +    }
    +
         /** Returns the builder for the settings used for calls to insert. */
         public UnaryCallSettings.Builder insertSettings() {
           return insertSettings;
         }
     
    +    /** Returns the builder for the settings used for calls to insert. */
    +    @BetaApi(
    +        "The surface for use by generated code is not stable yet and may change in the future.")
    +    public OperationCallSettings.Builder
    +        insertOperationSettings() {
    +      return insertOperationSettings;
    +    }
    +
         /** Returns the builder for the settings used for calls to list. */
         public PagedCallSettings.Builder
             listSettings() {
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java
    index afa275a6f5..2290fc6952 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java
    @@ -17,10 +17,9 @@
     package com.google.cloud.compute.v1.stub;
     
     import com.google.api.core.BetaApi;
    -import com.google.api.gax.core.BackgroundResource;
    -import com.google.api.gax.httpjson.ApiMessage;
     import com.google.api.gax.httpjson.HttpJsonCallSettings;
     import com.google.api.gax.httpjson.HttpJsonCallableFactory;
    +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable;
     import com.google.api.gax.httpjson.HttpJsonStubCallableFactory;
     import com.google.api.gax.rpc.BatchingCallSettings;
     import com.google.api.gax.rpc.ClientContext;
    @@ -29,6 +28,7 @@
     import com.google.api.gax.rpc.PagedCallSettings;
     import com.google.api.gax.rpc.UnaryCallSettings;
     import com.google.api.gax.rpc.UnaryCallable;
    +import com.google.cloud.compute.v1.Operation;
     import javax.annotation.Generated;
     
     // AUTO-GENERATED DOCUMENTATION AND CLASS.
    @@ -40,7 +40,7 @@
     @Generated("by gapic-generator-java")
     @BetaApi
     public class HttpJsonAddressesCallableFactory
    -    implements HttpJsonStubCallableFactory {
    +    implements HttpJsonStubCallableFactory {
     
       @Override
       public  UnaryCallable createUnaryCallable(
    @@ -75,10 +75,18 @@ public  UnaryCallable createBatchingCa
       @Override
       public 
           OperationCallable createOperationCallable(
    -          HttpJsonCallSettings httpJsonCallSettings,
    +          HttpJsonCallSettings httpJsonCallSettings,
               OperationCallSettings callSettings,
               ClientContext clientContext,
    -          BackgroundResource operationsStub) {
    -    return null;
    +          RegionOperationsStub operationsStub) {
    +    UnaryCallable innerCallable =
    +        HttpJsonCallableFactory.createBaseUnaryCallable(
    +            httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext);
    +    HttpJsonOperationSnapshotCallable initialCallable =
    +        new HttpJsonOperationSnapshotCallable(
    +            innerCallable,
    +            httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory());
    +    return HttpJsonCallableFactory.createOperationCallable(
    +        callSettings, clientContext, operationsStub.longRunningClient(), initialCallable);
       }
     }
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java
    index d8d960d342..679bfc1ae2 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java
    @@ -26,11 +26,14 @@
     import com.google.api.gax.core.BackgroundResourceAggregation;
     import com.google.api.gax.httpjson.ApiMethodDescriptor;
     import com.google.api.gax.httpjson.HttpJsonCallSettings;
    +import com.google.api.gax.httpjson.HttpJsonOperationSnapshot;
     import com.google.api.gax.httpjson.HttpJsonStubCallableFactory;
     import com.google.api.gax.httpjson.ProtoMessageRequestFormatter;
     import com.google.api.gax.httpjson.ProtoMessageResponseParser;
     import com.google.api.gax.httpjson.ProtoRestSerializer;
    +import com.google.api.gax.longrunning.OperationSnapshot;
     import com.google.api.gax.rpc.ClientContext;
    +import com.google.api.gax.rpc.OperationCallable;
     import com.google.api.gax.rpc.UnaryCallable;
     import com.google.cloud.compute.v1.AddressAggregatedList;
     import com.google.cloud.compute.v1.AddressList;
    @@ -39,6 +42,8 @@
     import com.google.cloud.compute.v1.InsertAddressRequest;
     import com.google.cloud.compute.v1.ListAddressesRequest;
     import com.google.cloud.compute.v1.Operation;
    +import com.google.cloud.compute.v1.Operation.Status;
    +import com.google.protobuf.TypeRegistry;
     import java.io.IOException;
     import java.util.ArrayList;
     import java.util.HashMap;
    @@ -56,6 +61,9 @@
     @Generated("by gapic-generator-java")
     @BetaApi("A restructuring of stub classes is planned, so this may break in the future")
     public class HttpJsonAddressesStub extends AddressesStub {
    +  private static final TypeRegistry typeRegistry =
    +      TypeRegistry.newBuilder().add(Operation.getDescriptor()).build();
    +
       private static final ApiMethodDescriptor
           aggregatedListMethodDescriptor =
               ApiMethodDescriptor.newBuilder()
    @@ -101,6 +109,7 @@ public class HttpJsonAddressesStub extends AddressesStub {
                   .setResponseParser(
                       ProtoMessageResponseParser.newBuilder()
                           .setDefaultInstance(AddressAggregatedList.getDefaultInstance())
    +                      .setDefaultTypeRegistry(typeRegistry)
                           .build())
                   .build();
     
    @@ -136,7 +145,21 @@ public class HttpJsonAddressesStub extends AddressesStub {
               .setResponseParser(
                   ProtoMessageResponseParser.newBuilder()
                       .setDefaultInstance(Operation.getDefaultInstance())
    +                  .setDefaultTypeRegistry(typeRegistry)
                       .build())
    +          .setOperationSnapshotFactory(
    +              (DeleteAddressRequest request, Operation response) -> {
    +                StringBuilder opName = new StringBuilder(response.getName());
    +                opName.append(":").append(request.getProject());
    +                opName.append(":").append(request.getRegion());
    +                return HttpJsonOperationSnapshot.newBuilder()
    +                    .setName(opName.toString())
    +                    .setMetadata(response)
    +                    .setDone(Status.DONE.equals(response.getStatus()))
    +                    .setResponse(response)
    +                    .setError(response.getHttpErrorStatusCode(), response.getHttpErrorMessage())
    +                    .build();
    +              })
               .build();
     
       private static final ApiMethodDescriptor insertMethodDescriptor =
    @@ -173,7 +196,21 @@ public class HttpJsonAddressesStub extends AddressesStub {
               .setResponseParser(
                   ProtoMessageResponseParser.newBuilder()
                       .setDefaultInstance(Operation.getDefaultInstance())
    +                  .setDefaultTypeRegistry(typeRegistry)
                       .build())
    +          .setOperationSnapshotFactory(
    +              (InsertAddressRequest request, Operation response) -> {
    +                StringBuilder opName = new StringBuilder(response.getName());
    +                opName.append(":").append(request.getProject());
    +                opName.append(":").append(request.getRegion());
    +                return HttpJsonOperationSnapshot.newBuilder()
    +                    .setName(opName.toString())
    +                    .setMetadata(response)
    +                    .setDone(Status.DONE.equals(response.getStatus()))
    +                    .setResponse(response)
    +                    .setError(response.getHttpErrorStatusCode(), response.getHttpErrorMessage())
    +                    .build();
    +              })
               .build();
     
       private static final ApiMethodDescriptor listMethodDescriptor =
    @@ -214,6 +251,7 @@ public class HttpJsonAddressesStub extends AddressesStub {
               .setResponseParser(
                   ProtoMessageResponseParser.newBuilder()
                       .setDefaultInstance(AddressList.getDefaultInstance())
    +                  .setDefaultTypeRegistry(typeRegistry)
                       .build())
               .build();
     
    @@ -222,11 +260,16 @@ public class HttpJsonAddressesStub extends AddressesStub {
       private final UnaryCallable
           aggregatedListPagedCallable;
       private final UnaryCallable deleteCallable;
    +  private final OperationCallable
    +      deleteOperationCallable;
       private final UnaryCallable insertCallable;
    +  private final OperationCallable
    +      insertOperationCallable;
       private final UnaryCallable listCallable;
       private final UnaryCallable listPagedCallable;
     
       private final BackgroundResource backgroundResources;
    +  private final HttpJsonRegionOperationsStub httpJsonOperationsStub;
       private final HttpJsonStubCallableFactory callableFactory;
     
       public static final HttpJsonAddressesStub create(AddressesStubSettings settings)
    @@ -265,23 +308,29 @@ protected HttpJsonAddressesStub(
           HttpJsonStubCallableFactory callableFactory)
           throws IOException {
         this.callableFactory = callableFactory;
    +    this.httpJsonOperationsStub =
    +        HttpJsonRegionOperationsStub.create(clientContext, callableFactory);
     
         HttpJsonCallSettings
             aggregatedListTransportSettings =
                 HttpJsonCallSettings.newBuilder()
                     .setMethodDescriptor(aggregatedListMethodDescriptor)
    +                .setTypeRegistry(typeRegistry)
                     .build();
         HttpJsonCallSettings deleteTransportSettings =
             HttpJsonCallSettings.newBuilder()
                 .setMethodDescriptor(deleteMethodDescriptor)
    +            .setTypeRegistry(typeRegistry)
                 .build();
         HttpJsonCallSettings insertTransportSettings =
             HttpJsonCallSettings.newBuilder()
                 .setMethodDescriptor(insertMethodDescriptor)
    +            .setTypeRegistry(typeRegistry)
                 .build();
         HttpJsonCallSettings listTransportSettings =
             HttpJsonCallSettings.newBuilder()
                 .setMethodDescriptor(listMethodDescriptor)
    +            .setTypeRegistry(typeRegistry)
                 .build();
     
         this.aggregatedListCallable =
    @@ -293,9 +342,21 @@ protected HttpJsonAddressesStub(
         this.deleteCallable =
             callableFactory.createUnaryCallable(
                 deleteTransportSettings, settings.deleteSettings(), clientContext);
    +    this.deleteOperationCallable =
    +        callableFactory.createOperationCallable(
    +            deleteTransportSettings,
    +            settings.deleteOperationSettings(),
    +            clientContext,
    +            httpJsonOperationsStub);
         this.insertCallable =
             callableFactory.createUnaryCallable(
                 insertTransportSettings, settings.insertSettings(), clientContext);
    +    this.insertOperationCallable =
    +        callableFactory.createOperationCallable(
    +            insertTransportSettings,
    +            settings.insertOperationSettings(),
    +            clientContext,
    +            httpJsonOperationsStub);
         this.listCallable =
             callableFactory.createUnaryCallable(
                 listTransportSettings, settings.listSettings(), clientContext);
    @@ -334,11 +395,21 @@ public UnaryCallable deleteCallable() {
         return deleteCallable;
       }
     
    +  @Override
    +  public OperationCallable deleteOperationCallable() {
    +    return deleteOperationCallable;
    +  }
    +
       @Override
       public UnaryCallable insertCallable() {
         return insertCallable;
       }
     
    +  @Override
    +  public OperationCallable insertOperationCallable() {
    +    return insertOperationCallable;
    +  }
    +
       @Override
       public UnaryCallable listCallable() {
         return listCallable;
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java
    index 6dac14a84e..16d93e6f94 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java
    @@ -17,11 +17,11 @@
     package com.google.cloud.compute.v1.stub;
     
     import com.google.api.core.BetaApi;
    -import com.google.api.gax.core.BackgroundResource;
    -import com.google.api.gax.httpjson.ApiMessage;
     import com.google.api.gax.httpjson.HttpJsonCallSettings;
     import com.google.api.gax.httpjson.HttpJsonCallableFactory;
    +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable;
     import com.google.api.gax.httpjson.HttpJsonStubCallableFactory;
    +import com.google.api.gax.httpjson.longrunning.stub.OperationsStub;
     import com.google.api.gax.rpc.BatchingCallSettings;
     import com.google.api.gax.rpc.ClientContext;
     import com.google.api.gax.rpc.OperationCallSettings;
    @@ -29,6 +29,7 @@
     import com.google.api.gax.rpc.PagedCallSettings;
     import com.google.api.gax.rpc.UnaryCallSettings;
     import com.google.api.gax.rpc.UnaryCallable;
    +import com.google.longrunning.Operation;
     import javax.annotation.Generated;
     
     // AUTO-GENERATED DOCUMENTATION AND CLASS.
    @@ -40,7 +41,7 @@
     @Generated("by gapic-generator-java")
     @BetaApi
     public class HttpJsonRegionOperationsCallableFactory
    -    implements HttpJsonStubCallableFactory {
    +    implements HttpJsonStubCallableFactory {
     
       @Override
       public  UnaryCallable createUnaryCallable(
    @@ -75,10 +76,18 @@ public  UnaryCallable createBatchingCa
       @Override
       public 
           OperationCallable createOperationCallable(
    -          HttpJsonCallSettings httpJsonCallSettings,
    +          HttpJsonCallSettings httpJsonCallSettings,
               OperationCallSettings callSettings,
               ClientContext clientContext,
    -          BackgroundResource operationsStub) {
    -    return null;
    +          OperationsStub operationsStub) {
    +    UnaryCallable innerCallable =
    +        HttpJsonCallableFactory.createBaseUnaryCallable(
    +            httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext);
    +    HttpJsonOperationSnapshotCallable initialCallable =
    +        new HttpJsonOperationSnapshotCallable(
    +            innerCallable,
    +            httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory());
    +    return HttpJsonCallableFactory.createOperationCallable(
    +        callSettings, clientContext, operationsStub.longRunningClient(), initialCallable);
       }
     }
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java
    index 9d90915792..0f081f8c40 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java
    @@ -23,16 +23,24 @@
     import com.google.api.gax.core.BackgroundResourceAggregation;
     import com.google.api.gax.httpjson.ApiMethodDescriptor;
     import com.google.api.gax.httpjson.HttpJsonCallSettings;
    +import com.google.api.gax.httpjson.HttpJsonLongRunningClient;
    +import com.google.api.gax.httpjson.HttpJsonOperationSnapshot;
     import com.google.api.gax.httpjson.HttpJsonStubCallableFactory;
     import com.google.api.gax.httpjson.ProtoMessageRequestFormatter;
     import com.google.api.gax.httpjson.ProtoMessageResponseParser;
     import com.google.api.gax.httpjson.ProtoRestSerializer;
    +import com.google.api.gax.longrunning.OperationSnapshot;
     import com.google.api.gax.rpc.ClientContext;
    +import com.google.api.gax.rpc.LongRunningClient;
     import com.google.api.gax.rpc.UnaryCallable;
     import com.google.cloud.compute.v1.GetRegionOperationRequest;
     import com.google.cloud.compute.v1.Operation;
    +import com.google.cloud.compute.v1.Operation.Status;
    +import com.google.cloud.compute.v1.WaitRegionOperationRequest;
    +import com.google.protobuf.TypeRegistry;
     import java.io.IOException;
     import java.util.ArrayList;
    +import java.util.Arrays;
     import java.util.HashMap;
     import java.util.List;
     import java.util.Map;
    @@ -48,6 +56,8 @@
     @Generated("by gapic-generator-java")
     @BetaApi("A restructuring of stub classes is planned, so this may break in the future")
     public class HttpJsonRegionOperationsStub extends RegionOperationsStub {
    +  private static final TypeRegistry typeRegistry = TypeRegistry.newBuilder().build();
    +
       private static final ApiMethodDescriptor
           getMethodDescriptor =
               ApiMethodDescriptor.newBuilder()
    @@ -78,12 +88,69 @@ public class HttpJsonRegionOperationsStub extends RegionOperationsStub {
                   .setResponseParser(
                       ProtoMessageResponseParser.newBuilder()
                           .setDefaultInstance(Operation.getDefaultInstance())
    +                      .setDefaultTypeRegistry(typeRegistry)
    +                      .build())
    +              .setOperationSnapshotFactory(
    +                  (GetRegionOperationRequest request, Operation response) -> {
    +                    StringBuilder opName = new StringBuilder(response.getName());
    +                    return HttpJsonOperationSnapshot.newBuilder()
    +                        .setName(opName.toString())
    +                        .setMetadata(response)
    +                        .setDone(Status.DONE.equals(response.getStatus()))
    +                        .setResponse(response)
    +                        .setError(response.getHttpErrorStatusCode(), response.getHttpErrorMessage())
    +                        .build();
    +                  })
    +              .setPollingRequestFactory(
    +                  compoundOperationId -> {
    +                    List idComponents = Arrays.asList(compoundOperationId.split(":"));
    +                    return GetRegionOperationRequest.newBuilder()
    +                        .setOperation(idComponents.get(0))
    +                        .setProject(idComponents.get(1))
    +                        .setRegion(idComponents.get(2))
    +                        .build();
    +                  })
    +              .build();
    +
    +  private static final ApiMethodDescriptor
    +      waitMethodDescriptor =
    +          ApiMethodDescriptor.newBuilder()
    +              .setFullMethodName("google.cloud.compute.v1.RegionOperations/Wait")
    +              .setHttpMethod(HttpMethods.POST)
    +              .setRequestFormatter(
    +                  ProtoMessageRequestFormatter.newBuilder()
    +                      .setPath(
    +                          "/compute/v1/projects/projects/{project}/regions/{region}/operations/{operation}/wait",
    +                          request -> {
    +                            Map fields = new HashMap<>();
    +                            ProtoRestSerializer serializer =
    +                                ProtoRestSerializer.create();
    +                            serializer.putPathParam(fields, "operation", request.getOperation());
    +                            serializer.putPathParam(fields, "project", request.getProject());
    +                            serializer.putPathParam(fields, "region", request.getRegion());
    +                            return fields;
    +                          })
    +                      .setQueryParamsExtractor(
    +                          request -> {
    +                            Map> fields = new HashMap<>();
    +                            ProtoRestSerializer serializer =
    +                                ProtoRestSerializer.create();
    +                            return fields;
    +                          })
    +                      .setRequestBodyExtractor(request -> null)
    +                      .build())
    +              .setResponseParser(
    +                  ProtoMessageResponseParser.newBuilder()
    +                      .setDefaultInstance(Operation.getDefaultInstance())
    +                      .setDefaultTypeRegistry(typeRegistry)
                           .build())
                   .build();
     
       private final UnaryCallable getCallable;
    +  private final UnaryCallable waitCallable;
     
       private final BackgroundResource backgroundResources;
    +  private final LongRunningClient longRunningClient;
       private final HttpJsonStubCallableFactory callableFactory;
     
       public static final HttpJsonRegionOperationsStub create(RegionOperationsStubSettings settings)
    @@ -128,12 +195,26 @@ protected HttpJsonRegionOperationsStub(
         HttpJsonCallSettings getTransportSettings =
             HttpJsonCallSettings.newBuilder()
                 .setMethodDescriptor(getMethodDescriptor)
    +            .setTypeRegistry(typeRegistry)
    +            .build();
    +    HttpJsonCallSettings waitTransportSettings =
    +        HttpJsonCallSettings.newBuilder()
    +            .setMethodDescriptor(waitMethodDescriptor)
    +            .setTypeRegistry(typeRegistry)
                 .build();
     
         this.getCallable =
             callableFactory.createUnaryCallable(
                 getTransportSettings, settings.getSettings(), clientContext);
    +    this.waitCallable =
    +        callableFactory.createUnaryCallable(
    +            waitTransportSettings, settings.waitSettings(), clientContext);
     
    +    this.longRunningClient =
    +        new HttpJsonLongRunningClient(
    +            getCallable,
    +            getMethodDescriptor.getOperationSnapshotFactory(),
    +            getMethodDescriptor.getPollingRequestFactory());
         this.backgroundResources =
             new BackgroundResourceAggregation(clientContext.getBackgroundResources());
       }
    @@ -142,6 +223,7 @@ protected HttpJsonRegionOperationsStub(
       public static List getMethodDescriptors() {
         List methodDescriptors = new ArrayList<>();
         methodDescriptors.add(getMethodDescriptor);
    +    methodDescriptors.add(waitMethodDescriptor);
         return methodDescriptors;
       }
     
    @@ -150,6 +232,16 @@ public UnaryCallable getCallable() {
         return getCallable;
       }
     
    +  @Override
    +  public UnaryCallable waitCallable() {
    +    return waitCallable;
    +  }
    +
    +  @Override
    +  public LongRunningClient longRunningClient() {
    +    return longRunningClient;
    +  }
    +
       @Override
       public final void close() {
         try {
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStub.java
    index c3019038cb..2d40fa610a 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStub.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStub.java
    @@ -16,10 +16,13 @@
     
     package com.google.cloud.compute.v1.stub;
     
    +import com.google.api.core.BetaApi;
     import com.google.api.gax.core.BackgroundResource;
    +import com.google.api.gax.rpc.LongRunningClient;
     import com.google.api.gax.rpc.UnaryCallable;
     import com.google.cloud.compute.v1.GetRegionOperationRequest;
     import com.google.cloud.compute.v1.Operation;
    +import com.google.cloud.compute.v1.WaitRegionOperationRequest;
     import javax.annotation.Generated;
     
     // AUTO-GENERATED DOCUMENTATION AND CLASS.
    @@ -31,10 +34,19 @@
     @Generated("by gapic-generator-java")
     public abstract class RegionOperationsStub implements BackgroundResource {
     
    +  @BetaApi
    +  public LongRunningClient longRunningClient() {
    +    throw new UnsupportedOperationException("Not implemented: longRunningClient()");
    +  }
    +
       public UnaryCallable getCallable() {
         throw new UnsupportedOperationException("Not implemented: getCallable()");
       }
     
    +  public UnaryCallable waitCallable() {
    +    throw new UnsupportedOperationException("Not implemented: waitCallable()");
    +  }
    +
       @Override
       public abstract void close();
     }
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStubSettings.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStubSettings.java
    index e968e9a2e6..365c834255 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStubSettings.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStubSettings.java
    @@ -33,6 +33,7 @@
     import com.google.api.gax.rpc.UnaryCallSettings;
     import com.google.cloud.compute.v1.GetRegionOperationRequest;
     import com.google.cloud.compute.v1.Operation;
    +import com.google.cloud.compute.v1.WaitRegionOperationRequest;
     import com.google.common.collect.ImmutableList;
     import com.google.common.collect.ImmutableMap;
     import com.google.common.collect.ImmutableSet;
    @@ -85,12 +86,18 @@ public class RegionOperationsStubSettings extends StubSettings getSettings;
    +  private final UnaryCallSettings waitSettings;
     
       /** Returns the object with the settings used for calls to get. */
       public UnaryCallSettings getSettings() {
         return getSettings;
       }
     
    +  /** Returns the object with the settings used for calls to wait. */
    +  public UnaryCallSettings waitSettings() {
    +    return waitSettings;
    +  }
    +
       @BetaApi("A restructuring of stub classes is planned, so this may break in the future")
       public RegionOperationsStub createStub() throws IOException {
         if (getTransportChannelProvider()
    @@ -169,12 +176,14 @@ protected RegionOperationsStubSettings(Builder settingsBuilder) throws IOExcepti
         super(settingsBuilder);
     
         getSettings = settingsBuilder.getSettings().build();
    +    waitSettings = settingsBuilder.waitSettings().build();
       }
     
       /** Builder for RegionOperationsStubSettings. */
       public static class Builder extends StubSettings.Builder {
         private final ImmutableList> unaryMethodSettingsBuilders;
         private final UnaryCallSettings.Builder getSettings;
    +    private final UnaryCallSettings.Builder waitSettings;
         private static final ImmutableMap>
             RETRYABLE_CODE_DEFINITIONS;
     
    @@ -186,6 +195,7 @@ public static class Builder extends StubSettings.BuildernewArrayList(
                       StatusCode.Code.DEADLINE_EXCEEDED, StatusCode.Code.UNAVAILABLE)));
    +      definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList()));
           RETRYABLE_CODE_DEFINITIONS = definitions.build();
         }
     
    @@ -205,6 +215,8 @@ public static class Builder extends StubSettings.Builder>of(getSettings);
    +      unaryMethodSettingsBuilders =
    +          ImmutableList.>of(getSettings, waitSettings);
           initDefaults(this);
         }
     
    @@ -225,8 +239,10 @@ protected Builder(RegionOperationsStubSettings settings) {
           super(settings);
     
           getSettings = settings.getSettings.toBuilder();
    +      waitSettings = settings.waitSettings.toBuilder();
     
    -      unaryMethodSettingsBuilders = ImmutableList.>of(getSettings);
    +      unaryMethodSettingsBuilders =
    +          ImmutableList.>of(getSettings, waitSettings);
         }
     
         private static Builder createDefault() {
    @@ -248,6 +264,11 @@ private static Builder initDefaults(Builder builder) {
               .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_0_codes"))
               .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_0_params"));
     
    +      builder
    +          .waitSettings()
    +          .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes"))
    +          .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params"));
    +
           return builder;
         }
     
    @@ -271,6 +292,11 @@ public UnaryCallSettings.Builder getSettin
           return getSettings;
         }
     
    +    /** Returns the builder for the settings used for calls to wait. */
    +    public UnaryCallSettings.Builder waitSettings() {
    +      return waitSettings;
    +    }
    +
         @Override
         public RegionOperationsStubSettings build() throws IOException {
           return new RegionOperationsStubSettings(this);
    diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java
    index a6adbe6945..01e6bd03a6 100644
    --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java
    +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java
    @@ -485,6 +485,7 @@ public final Subscription createSubscription(
        *           .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build())
        *           .setRetryPolicy(RetryPolicy.newBuilder().build())
        *           .setDetached(true)
    +   *           .setTopicMessageRetentionDuration(Duration.newBuilder().build())
        *           .build();
        *   Subscription response = subscriptionAdminClient.createSubscription(request);
        * }
    @@ -529,6 +530,7 @@ public final Subscription createSubscription(Subscription request) {
        *           .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build())
        *           .setRetryPolicy(RetryPolicy.newBuilder().build())
        *           .setDetached(true)
    +   *           .setTopicMessageRetentionDuration(Duration.newBuilder().build())
        *           .build();
        *   ApiFuture future =
        *       subscriptionAdminClient.createSubscriptionCallable().futureCall(request);
    diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClientTest.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClientTest.java
    index dd1bd27dac..9d53a7554a 100644
    --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClientTest.java
    +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClientTest.java
    @@ -149,6 +149,7 @@ public void createSubscriptionTest() throws Exception {
                 .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build())
                 .setRetryPolicy(RetryPolicy.newBuilder().build())
                 .setDetached(true)
    +            .setTopicMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockSubscriber.addResponse(expectedResponse);
     
    @@ -209,6 +210,7 @@ public void createSubscriptionTest2() throws Exception {
                 .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build())
                 .setRetryPolicy(RetryPolicy.newBuilder().build())
                 .setDetached(true)
    +            .setTopicMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockSubscriber.addResponse(expectedResponse);
     
    @@ -269,6 +271,7 @@ public void createSubscriptionTest3() throws Exception {
                 .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build())
                 .setRetryPolicy(RetryPolicy.newBuilder().build())
                 .setDetached(true)
    +            .setTopicMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockSubscriber.addResponse(expectedResponse);
     
    @@ -329,6 +332,7 @@ public void createSubscriptionTest4() throws Exception {
                 .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build())
                 .setRetryPolicy(RetryPolicy.newBuilder().build())
                 .setDetached(true)
    +            .setTopicMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockSubscriber.addResponse(expectedResponse);
     
    @@ -389,6 +393,7 @@ public void getSubscriptionTest() throws Exception {
                 .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build())
                 .setRetryPolicy(RetryPolicy.newBuilder().build())
                 .setDetached(true)
    +            .setTopicMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockSubscriber.addResponse(expectedResponse);
     
    @@ -439,6 +444,7 @@ public void getSubscriptionTest2() throws Exception {
                 .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build())
                 .setRetryPolicy(RetryPolicy.newBuilder().build())
                 .setDetached(true)
    +            .setTopicMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockSubscriber.addResponse(expectedResponse);
     
    @@ -489,6 +495,7 @@ public void updateSubscriptionTest() throws Exception {
                 .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build())
                 .setRetryPolicy(RetryPolicy.newBuilder().build())
                 .setDetached(true)
    +            .setTopicMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockSubscriber.addResponse(expectedResponse);
     
    diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClient.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClient.java
    index 802fe3e940..be0a3a2e42 100644
    --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClient.java
    +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClient.java
    @@ -237,6 +237,7 @@ public final Topic createTopic(String name) {
        *           .setKmsKeyName("kmsKeyName412586233")
        *           .setSchemaSettings(SchemaSettings.newBuilder().build())
        *           .setSatisfiesPzs(true)
    +   *           .setMessageRetentionDuration(Duration.newBuilder().build())
        *           .build();
        *   Topic response = topicAdminClient.createTopic(request);
        * }
    @@ -266,6 +267,7 @@ public final Topic createTopic(Topic request) {
        *           .setKmsKeyName("kmsKeyName412586233")
        *           .setSchemaSettings(SchemaSettings.newBuilder().build())
        *           .setSatisfiesPzs(true)
    +   *           .setMessageRetentionDuration(Duration.newBuilder().build())
        *           .build();
        *   ApiFuture future = topicAdminClient.createTopicCallable().futureCall(request);
        *   // Do something.
    diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClientTest.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClientTest.java
    index 09b8de0f90..02d6a55850 100644
    --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClientTest.java
    +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClientTest.java
    @@ -37,6 +37,7 @@
     import com.google.iam.v1.TestIamPermissionsResponse;
     import com.google.protobuf.AbstractMessage;
     import com.google.protobuf.ByteString;
    +import com.google.protobuf.Duration;
     import com.google.protobuf.Empty;
     import com.google.protobuf.FieldMask;
     import com.google.pubsub.v1.DeleteTopicRequest;
    @@ -125,6 +126,7 @@ public void createTopicTest() throws Exception {
                 .setKmsKeyName("kmsKeyName412586233")
                 .setSchemaSettings(SchemaSettings.newBuilder().build())
                 .setSatisfiesPzs(true)
    +            .setMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockPublisher.addResponse(expectedResponse);
     
    @@ -168,6 +170,7 @@ public void createTopicTest2() throws Exception {
                 .setKmsKeyName("kmsKeyName412586233")
                 .setSchemaSettings(SchemaSettings.newBuilder().build())
                 .setSatisfiesPzs(true)
    +            .setMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockPublisher.addResponse(expectedResponse);
     
    @@ -211,6 +214,7 @@ public void updateTopicTest() throws Exception {
                 .setKmsKeyName("kmsKeyName412586233")
                 .setSchemaSettings(SchemaSettings.newBuilder().build())
                 .setSatisfiesPzs(true)
    +            .setMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockPublisher.addResponse(expectedResponse);
     
    @@ -341,6 +345,7 @@ public void getTopicTest() throws Exception {
                 .setKmsKeyName("kmsKeyName412586233")
                 .setSchemaSettings(SchemaSettings.newBuilder().build())
                 .setSatisfiesPzs(true)
    +            .setMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockPublisher.addResponse(expectedResponse);
     
    @@ -384,6 +389,7 @@ public void getTopicTest2() throws Exception {
                 .setKmsKeyName("kmsKeyName412586233")
                 .setSchemaSettings(SchemaSettings.newBuilder().build())
                 .setSatisfiesPzs(true)
    +            .setMessageRetentionDuration(Duration.newBuilder().build())
                 .build();
         mockPublisher.addResponse(expectedResponse);