Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

Commit

Permalink
feat: add DIREGAPIC support for PHP (#3305)
Browse files Browse the repository at this point in the history
  • Loading branch information
bshaffer committed Dec 8, 2020
1 parent 994ffa2 commit 0456289
Show file tree
Hide file tree
Showing 15 changed files with 8,545 additions and 35 deletions.
6 changes: 4 additions & 2 deletions rules_gapic/php/php_gapic.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ _php_gapic_postprocessed_srcjar = rule(
},
)

def php_gapic_srcjar(name, src, gapic_yaml, service_yaml, package, grpc_service_config = None, **kwargs):
def php_gapic_srcjar(name, src, gapic_yaml, service_yaml, package, grpc_service_config = None, transport = None, **kwargs):
raw_srcjar_name = "%s_raw" % name

gapic_srcjar(
Expand All @@ -128,6 +128,7 @@ def php_gapic_srcjar(name, src, gapic_yaml, service_yaml, package, grpc_service_
language = "php",
package = package,
grpc_service_config = grpc_service_config,
transport = transport,
**kwargs
)

Expand All @@ -137,7 +138,7 @@ def php_gapic_srcjar(name, src, gapic_yaml, service_yaml, package, grpc_service_
**kwargs
)

def php_gapic_library(name, src, gapic_yaml, service_yaml, package = None, deps = [], grpc_service_config = None, **kwargs):
def php_gapic_library(name, src, gapic_yaml, service_yaml, package = None, deps = [], grpc_service_config = None, transport = None, **kwargs):
srcjar_name = "%s_srcjar" % name

php_gapic_srcjar(
Expand All @@ -147,6 +148,7 @@ def php_gapic_library(name, src, gapic_yaml, service_yaml, package = None, deps
service_yaml = service_yaml,
package = package,
grpc_service_config = grpc_service_config,
transport = transport,
**kwargs
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import static com.google.api.codegen.metacode.InitCodeLineType.MapInitLine;

import com.google.api.codegen.common.TargetLanguage;
import com.google.api.codegen.config.BatchingConfig;
import com.google.api.codegen.config.FieldConfig;
import com.google.api.codegen.config.FieldModel;
Expand Down Expand Up @@ -88,6 +89,7 @@ public TestCaseView createTestCaseView(
clientMethodType,
Synchronicity.Sync,
null,
null,
null);
}

Expand All @@ -98,7 +100,8 @@ public TestCaseView createTestCaseView(
ClientMethodType clientMethodType,
Synchronicity synchronicity,
InitCodeContext requestObjectInitCodeContext,
MethodContext requestObjectMethodContext) {
MethodContext requestObjectMethodContext,
TargetLanguage targetLanguage) {
MethodModel method = methodContext.getMethodModel();
MethodConfig methodConfig = methodContext.getMethodConfig();
SurfaceNamer namer = methodContext.getNamer();
Expand Down Expand Up @@ -224,7 +227,7 @@ public TestCaseView createTestCaseView(
.createStubFunctionName(namer.getCreateStubFunctionName(methodContext.getTargetInterface()))
.grpcStubCallString(namer.getGrpcStubCallString(methodContext.getTargetInterface(), method))
.clientHasDefaultInstance(methodContext.getInterfaceConfig().hasDefaultInstance())
.methodDescriptor(getMethodDescriptorName(methodContext))
.methodDescriptor(getMethodDescriptorName(methodContext, targetLanguage))
.grpcMethodName(
synchronicity == Synchronicity.Sync
? namer.getGrpcMethodName(method)
Expand All @@ -233,8 +236,9 @@ public TestCaseView createTestCaseView(
.build();
}

private String getMethodDescriptorName(MethodContext context) {
if (context.getProductConfig().getTransportProtocol().equals(TransportProtocol.HTTP)) {
private String getMethodDescriptorName(MethodContext context, TargetLanguage targetLanguage) {
if (context.getProductConfig().getTransportProtocol().equals(TransportProtocol.HTTP)
&& targetLanguage == TargetLanguage.JAVA) {
TypeName rpcStubClassName =
new TypeName(
context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ private TestCaseView createRequestObjectTestCase(
: ClientMethodType.AsyncRequestObjectCallSettingsMethod,
synchronicity,
null,
null,
null);
}

Expand Down Expand Up @@ -289,6 +290,7 @@ private TestCaseView createFlattenedTestCase(
clientMethodType,
synchronicity,
initCodeRequestObjectContext,
requestContext);
requestContext,
null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package com.google.api.codegen.transformer.java;

import com.google.api.codegen.common.TargetLanguage;
import com.google.api.codegen.config.ApiModel;
import com.google.api.codegen.config.FlatteningConfig;
import com.google.api.codegen.config.FlatteningConfigs;
Expand All @@ -37,6 +38,7 @@
import com.google.api.codegen.transformer.StaticLangApiMethodTransformer;
import com.google.api.codegen.transformer.SurfaceNamer;
import com.google.api.codegen.transformer.SurfaceTransformer;
import com.google.api.codegen.transformer.Synchronicity;
import com.google.api.codegen.transformer.TestCaseTransformer;
import com.google.api.codegen.util.SymbolTable;
import com.google.api.codegen.util.TypeName;
Expand Down Expand Up @@ -311,7 +313,14 @@ private List<TestCaseView> createTestCaseViews(InterfaceContext context) {
valueGenerator);
testCaseViews.add(
testCaseTransformer.createTestCaseView(
methodContext, testNameTable, initCodeContext, clientMethodType));
methodContext,
testNameTable,
initCodeContext,
clientMethodType,
Synchronicity.Sync,
null,
null,
TargetLanguage.JAVA));
}
} else {
MethodContext methodContext = context.asRequestMethodContext(method);
Expand All @@ -325,7 +334,14 @@ private List<TestCaseView> createTestCaseViews(InterfaceContext context) {
valueGenerator);
TestCaseView testCaseView =
testCaseTransformer.createTestCaseView(
methodContext, testNameTable, initCodeContext, clientMethodType);
methodContext,
testNameTable,
initCodeContext,
clientMethodType,
Synchronicity.Sync,
null,
null,
TargetLanguage.JAVA);
testCaseViews.add(testCaseView);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ private DynamicLangXApiView.Builder prepareApiClassBuilder(GapicInterfaceContext
xapiClass.grpcClientTypeName(
namer.getAndSaveNicknameForGrpcClientTypeName(
context.getImportTypeTable(), context.getInterfaceModel()));
xapiClass.supportsGrpcTransport(true);

xapiClass.apiMethods(new ArrayList<>(methods));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.api.codegen.config.MethodModel;
import com.google.api.codegen.config.ProductServiceConfig;
import com.google.api.codegen.config.ProtoApiModel;
import com.google.api.codegen.config.TransportProtocol;
import com.google.api.codegen.config.TypeModel;
import com.google.api.codegen.config.VisibilityConfig;
import com.google.api.codegen.gapic.GapicCodePathMapper;
Expand Down Expand Up @@ -73,6 +74,7 @@

/** The ModelToViewTransformer to transform a Model into the standard GAPIC surface in PHP. */
public class PhpGapicSurfaceTransformer implements ModelToViewTransformer<ProtoApiModel> {
private GapicProductConfig productConfig;
private Model serviceModel;
private GapicCodePathMapper pathMapper;
private ServiceTransformer serviceTransformer;
Expand All @@ -98,6 +100,7 @@ public class PhpGapicSurfaceTransformer implements ModelToViewTransformer<ProtoA

public PhpGapicSurfaceTransformer(
GapicProductConfig productConfig, GapicCodePathMapper pathMapper, Model serviceModel) {
this.productConfig = productConfig;
this.serviceModel = serviceModel;
this.pathMapper = pathMapper;
this.serviceTransformer = new ServiceTransformer();
Expand Down Expand Up @@ -164,6 +167,7 @@ private ViewModel buildGapicClientViewModel(GapicInterfaceContext context) {
serviceTransformer.generateServiceDoc(context, methods.get(0), context.getProductConfig()));

apiImplClass.templateFileName(API_IMPL_TEMPLATE_FILENAME);
apiImplClass.supportsGrpcTransport(supportsGrpcTransport());
apiImplClass.protoFilename(context.getInterface().getFile().getSimpleName());
String implName = namer.getApiWrapperClassImplName(context.getInterfaceConfig());
apiImplClass.name(implName);
Expand Down Expand Up @@ -191,15 +195,22 @@ private ViewModel buildGapicClientViewModel(GapicInterfaceContext context) {
apiImplClass.clientConfigPath(namer.getClientConfigPath(context.getInterfaceConfig()));
apiImplClass.clientConfigName(namer.getClientConfigName(context.getInterfaceConfig()));
apiImplClass.interfaceKey(context.getInterface().getFullName());
String grpcClientTypeName =
namer.getAndSaveNicknameForGrpcClientTypeName(
context.getImportTypeTable(), context.getInterfaceModel());
apiImplClass.grpcClientTypeName(grpcClientTypeName);
if (supportsGrpcTransport()) {
// PHP generates a client that supports both gRPC and REST
String grpcClientTypeName =
namer.getAndSaveNicknameForGrpcClientTypeName(
context.getImportTypeTable(), context.getInterfaceModel());
apiImplClass.grpcClientTypeName(grpcClientTypeName);

apiImplClass.stubs(grpcStubTransformer.generateGrpcStubs(context));
} else {
// PHP generates a client that only supports REST
apiImplClass.grpcClientTypeName("");
apiImplClass.stubs(new ArrayList<>());
}

apiImplClass.apiMethods(methods.stream().collect(Collectors.toList()));

apiImplClass.stubs(grpcStubTransformer.generateGrpcStubs(context));

apiImplClass.hasDefaultServiceAddress(context.getInterfaceConfig().hasDefaultServiceAddress());
apiImplClass.hasDefaultServiceScopes(context.getInterfaceConfig().hasDefaultServiceScopes());

Expand Down Expand Up @@ -426,6 +437,9 @@ private List<GrpcStreamingDetailView> createGrpcStreamingDescriptors(
List<GrpcStreamingDetailView> result = new ArrayList<>();

for (MethodModel method : context.getGrpcStreamingMethods()) {
if (!supportsGrpcTransport()) {
throw new RuntimeException("Streaming methods only valid for gRPC transport");
}
GrpcStreamingConfig grpcStreamingConfig =
context.asRequestMethodContext(method).getMethodConfig().getGrpcStreaming();
String resourcesFieldGetFunction = null;
Expand Down Expand Up @@ -453,12 +467,15 @@ private void addApiImports(GapicInterfaceContext context) {
typeTable.saveNicknameFor("\\Google\\ApiCore\\CredentialsWrapper");
typeTable.saveNicknameFor("\\Google\\ApiCore\\GapicClientTrait");
typeTable.saveNicknameFor("\\Google\\ApiCore\\PathTemplate");
typeTable.saveNicknameFor("\\Google\\ApiCore\\RequestParamsHeaderDescriptor");
typeTable.saveNicknameFor("\\Google\\ApiCore\\RetrySettings");
typeTable.saveNicknameFor("\\Google\\ApiCore\\Transport\\TransportInterface");
typeTable.saveNicknameFor("\\Google\\ApiCore\\ValidationException");
typeTable.saveNicknameFor("\\Google\\Auth\\FetchAuthTokenInterface");

if (supportsGrpcTransport()) {
typeTable.saveNicknameFor("\\Google\\ApiCore\\RequestParamsHeaderDescriptor");
}

if (interfaceConfig.hasLongRunningOperations()) {
typeTable.saveNicknameFor("\\Google\\ApiCore\\LongRunning\\OperationsClient");
typeTable.saveNicknameFor("\\Google\\ApiCore\\OperationResponse");
Expand Down Expand Up @@ -529,4 +546,8 @@ private Map.Entry<String, String> getHttpMethodEntry(HttpRule httpRule) {

throw new IllegalStateException("A HTTP method must be defined.");
}

private boolean supportsGrpcTransport() {
return productConfig.getTransportProtocol().equals(TransportProtocol.GRPC);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ private DynamicLangXApiView.Builder generateApiView(GapicInterfaceContext contex
xapiClass.grpcTransportClassName(namer.getGrpcTransportClassName(context.getInterfaceConfig()));
xapiClass.grpcTransportImportName(
namer.getGrpcTransportImportName(context.getInterfaceConfig()));
xapiClass.supportsGrpcTransport(true);

// Generate the view for the API class.
xapiClass.name(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ private ViewModel generateApiClass(GapicInterfaceContext context, String package
xapiClass.grpcClientTypeName(
namer.getAndSaveNicknameForGrpcClientTypeName(
context.getImportTypeTable(), context.getInterfaceModel()));
xapiClass.supportsGrpcTransport(true);

xapiClass.apiMethods(methods);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ public boolean hasMissingDefaultOptions() {
@Nullable
public abstract String grpcTransportImportName();

public abstract boolean supportsGrpcTransport();

@Override
public String resourceRoot() {
return SnippetSetRunner.SNIPPET_RESOURCE_ROOT;
Expand Down Expand Up @@ -215,6 +217,8 @@ public abstract static class Builder {

public abstract Builder grpcTransportImportName(String val);

public abstract Builder supportsGrpcTransport(boolean val);

public abstract DynamicLangXApiView build();
}
}
70 changes: 51 additions & 19 deletions src/main/resources/com/google/api/codegen/php/client_impl.snip
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@
@end
'clientConfig' => __DIR__ . '{@xapiClass.clientConfigPath}',
'descriptorsConfigPath' => __DIR__ . '/../resources/{@xapiClass.clientConfigName}_descriptor_config.php',
'gcpApiConfigPath' => __DIR__ . '/../resources/{@xapiClass.clientConfigName}_grpc_config.json',
@if xapiClass.supportsGrpcTransport
'gcpApiConfigPath' => __DIR__ . '/../resources/{@xapiClass.clientConfigName}_grpc_config.json',
@end
'credentialsConfig' => [
@if xapiClass.hasDefaultServiceScopes
'defaultScopes' => self::$serviceScopes,
Expand All @@ -156,6 +158,17 @@
@if xapiClass.hasFormatOrParseResourceFunctions
{@parseNameFunction(xapiClass)}
@end
@if not(xapiClass.supportsGrpcTransport)
private static function defaultTransport()
{
return 'rest';
}

private static function getSupportedTransports()
{
return ['rest'];
}
@end
{@""}
@end

Expand Down Expand Up @@ -348,24 +361,43 @@
* path to a JSON file, or a PHP array containing the decoded JSON data.
* By default this settings points to the default client config file, which is provided
* in the resources folder.
* @@type string|TransportInterface $transport
* The transport used for executing network requests. May be either the string `rest`
* or `grpc`. Defaults to `grpc` if gRPC support is detected on the system.
* *Advanced usage*: Additionally, it is possible to pass in an already instantiated
* {@@see \Google\ApiCore\Transport\TransportInterface} object. Note that when this
* object is provided, any settings in $transportConfig, and any $serviceAddress
* setting, will be ignored.
* @@type array $transportConfig
* Configuration options that will be used to construct the transport. Options for
* each supported transport type should be passed in a key for that transport. For
* example:
* $transportConfig = [
* 'grpc' => [...],
* 'rest' => [...]
* ];
* See the {@@see \Google\ApiCore\Transport\GrpcTransport::build()} and
* {@@see \Google\ApiCore\Transport\RestTransport::build()} methods for the
* supported options.
@if xapiClass.supportsGrpcTransport
* @@type string|TransportInterface $transport
* The transport used for executing network requests. May be either the string `rest`
* or `grpc`. Defaults to `grpc` if gRPC support is detected on the system.
* *Advanced usage*: Additionally, it is possible to pass in an already instantiated
* {@@see \Google\ApiCore\Transport\TransportInterface} object. Note that when this
* object is provided, any settings in $transportConfig, and any $serviceAddress
* setting, will be ignored.
* @@type array $transportConfig
* Configuration options that will be used to construct the transport. Options for
* each supported transport type should be passed in a key for that transport. For
* example:
* $transportConfig = [
* 'grpc' => [...],
* 'rest' => [...]
* ];
* See the {@@see \Google\ApiCore\Transport\GrpcTransport::build()} and
* {@@see \Google\ApiCore\Transport\RestTransport::build()} methods for the
* supported options.
@else
* @@type string|TransportInterface $transport
* The transport used for executing network requests. At the moment, only supports
* `rest`.
* *Advanced usage*: Additionally, it is possible to pass in an already instantiated
* {@@see \Google\ApiCore\Transport\TransportInterface} object. Note that when this
* object is provided, any settings in $transportConfig, and any $serviceAddress
* setting, will be ignored.
* @@type array $transportConfig
* Configuration options that will be used to construct the transport. Options for
* each supported transport type should be passed in a key for that transport. For
* example:
* $transportConfig = [
* 'rest' => [...]
* ];
* See the {@@see \Google\ApiCore\Transport\RestTransport::build()} method for the
* supported options.
@end
* }
* @@throws ValidationException
* @@experimental
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,19 @@ public static List<Object[]> testedConfigs() {
TransportProtocol.GRPC,
"common_resources",
"another_service"),
GapicTestBase2.createTestConfig(
TargetLanguage.PHP,
new String[] {"library_rest_v2_gapic.yaml"},
"library_pkg2.yaml",
"library_rest",
"google.example.library.v1",
null,
null,
null,
null,
TransportProtocol.HTTP,
"common_resources",
"another_service"),
GapicTestBase2.createTestConfig(
TargetLanguage.NODEJS,
new String[] {"library_v2_gapic.yaml"},
Expand Down
Loading

0 comments on commit 0456289

Please sign in to comment.