com.google.api.codegen.config.GapicInterfaceConfig.java Source code

Java tutorial

Introduction

Here is the source code for com.google.api.codegen.config.GapicInterfaceConfig.java

Source

/* Copyright 2016 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.codegen.config;

import com.google.api.codegen.CollectionConfigProto;
import com.google.api.codegen.IamResourceProto;
import com.google.api.codegen.InterfaceConfigProto;
import com.google.api.codegen.MethodConfigProto;
import com.google.api.codegen.RetryParamsDefinitionProto;
import com.google.api.codegen.common.TargetLanguage;
import com.google.api.codegen.transformer.RetryDefinitionsTransformer;
import com.google.api.tools.framework.model.Diag;
import com.google.api.tools.framework.model.DiagCollector;
import com.google.api.tools.framework.model.Field;
import com.google.api.tools.framework.model.Interface;
import com.google.api.tools.framework.model.Method;
import com.google.api.tools.framework.model.Model;
import com.google.api.tools.framework.model.SimpleLocation;
import com.google.api.tools.framework.model.TypeRef;
import com.google.auto.value.AutoValue;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;

/**
 * GapicInterfaceConfig represents the client code-gen config for an API interface, and includes the
 * configuration for methods and resource names.
 *
 * <p>In grpc-based Gapic clients, an API interface is defined by a "service" section in a proto
 * file.
 */
@AutoValue
public abstract class GapicInterfaceConfig implements InterfaceConfig {

    private static final String SERVICE_ADDRESS_PARAM = "service_address";
    private static final String SCOPES_PARAM = "scopes";
    private static final ImmutableSet<String> CONSTRUCTOR_PARAMS = ImmutableSet.<String>of(SERVICE_ADDRESS_PARAM,
            SCOPES_PARAM);

    public Interface getInterface() {
        return getInterfaceModel().getInterface();
    }

    @Override
    public abstract ProtoInterfaceModel getInterfaceModel();

    @Override
    public abstract List<GapicMethodConfig> getMethodConfigs();

    @Nullable
    @Override
    public abstract SmokeTestConfig getSmokeTestConfig();

    abstract ImmutableMap<String, GapicMethodConfig> getMethodConfigMap();

    @Override
    public abstract ImmutableMap<String, ImmutableSet<String>> getRetryCodesDefinition();

    @Override
    public abstract ImmutableMap<String, RetryParamsDefinitionProto> getRetrySettingsDefinition();

    @Override
    public abstract ImmutableList<FieldModel> getIamResources();

    @Override
    public abstract ImmutableList<String> getRequiredConstructorParams();

    @Override
    public abstract ImmutableList<SingleResourceNameConfig> getSingleResourceNameConfigs();

    @Override
    public abstract String getManualDoc();

    @Override
    public String getName() {
        return getInterfaceNameOverride() != null ? getInterfaceNameOverride() : getInterface().getSimpleName();
    }

    @Override
    public String getRawName() {
        return getInterface().getSimpleName();
    }

    /**
     * Creates an instance of GapicInterfaceConfig based on ConfigProto, linking up method
     * configurations with specified methods in methodConfigMap. On errors, null will be returned, and
     * diagnostics are reported to the model.
     */
    @Nullable
    static GapicInterfaceConfig createInterfaceConfig(DiagCollector diagCollector, TargetLanguage language,
            InterfaceConfigProto interfaceConfigProto, Interface apiInterface, String interfaceNameOverride,
            ResourceNameMessageConfigs messageConfigs,
            ImmutableMap<String, ResourceNameConfig> resourceNameConfigs) {

        ImmutableMap<String, ImmutableSet<String>> retryCodesDefinition = RetryDefinitionsTransformer
                .createRetryCodesDefinition(diagCollector, interfaceConfigProto);
        ImmutableMap<String, RetryParamsDefinitionProto> retrySettingsDefinition = RetryDefinitionsTransformer
                .createRetrySettingsDefinition(interfaceConfigProto);

        List<GapicMethodConfig> methodConfigs = null;
        ImmutableMap<String, GapicMethodConfig> methodConfigMap = null;
        if (retryCodesDefinition != null && retrySettingsDefinition != null) {
            methodConfigMap = createMethodConfigMap(diagCollector, language, interfaceConfigProto, apiInterface,
                    messageConfigs, resourceNameConfigs, retryCodesDefinition.keySet(),
                    retrySettingsDefinition.keySet());
            methodConfigs = createMethodConfigs(methodConfigMap, interfaceConfigProto);
        }

        SmokeTestConfig smokeTestConfig = createSmokeTestConfig(diagCollector, apiInterface, interfaceConfigProto);

        ImmutableList<FieldModel> iamResources = createIamResources(apiInterface.getModel(),
                interfaceConfigProto.getExperimentalFeatures().getIamResourcesList());

        ImmutableList<String> requiredConstructorParams = ImmutableList
                .<String>copyOf(interfaceConfigProto.getRequiredConstructorParamsList());
        for (String param : interfaceConfigProto.getRequiredConstructorParamsList()) {
            if (!CONSTRUCTOR_PARAMS.contains(param)) {
                diagCollector
                        .addDiag(Diag.error(SimpleLocation.TOPLEVEL, "Unsupported constructor param: %s", param));
            }
        }

        ImmutableList.Builder<SingleResourceNameConfig> resourcesBuilder = ImmutableList.builder();
        for (CollectionConfigProto collectionConfigProto : interfaceConfigProto.getCollectionsList()) {
            String entityName = collectionConfigProto.getEntityName();
            ResourceNameConfig resourceName = resourceNameConfigs.get(entityName);
            if (resourceName == null || !(resourceName instanceof SingleResourceNameConfig)) {
                diagCollector.addDiag(Diag.error(SimpleLocation.TOPLEVEL,
                        "Inconsistent configuration - single resource name %s specified for interface, "
                                + " but was not found in GapicProductConfig configuration.",
                        entityName));
                return null;
            }
            resourcesBuilder.add((SingleResourceNameConfig) resourceName);
        }
        ImmutableList<SingleResourceNameConfig> singleResourceNames = resourcesBuilder.build();

        String manualDoc = Strings
                .nullToEmpty(interfaceConfigProto.getLangDoc().get(language.toString().toLowerCase())).trim();

        if (diagCollector.hasErrors()) {
            return null;
        } else {
            return new AutoValue_GapicInterfaceConfig(interfaceNameOverride, new ProtoInterfaceModel(apiInterface),
                    methodConfigs, smokeTestConfig, methodConfigMap, retryCodesDefinition, retrySettingsDefinition,
                    iamResources, requiredConstructorParams, singleResourceNames, manualDoc);
        }
    }

    private static SmokeTestConfig createSmokeTestConfig(DiagCollector diagCollector, Interface apiInterface,
            InterfaceConfigProto interfaceConfigProto) {
        if (interfaceConfigProto.hasSmokeTest()) {
            return SmokeTestConfig.createSmokeTestConfig(new ProtoInterfaceModel(apiInterface),
                    interfaceConfigProto.getSmokeTest(), diagCollector);
        } else {
            return null;
        }
    }

    private static ImmutableMap<String, GapicMethodConfig> createMethodConfigMap(DiagCollector diagCollector,
            TargetLanguage language, InterfaceConfigProto interfaceConfigProto, Interface apiInterface,
            ResourceNameMessageConfigs messageConfigs, ImmutableMap<String, ResourceNameConfig> resourceNameConfigs,
            ImmutableSet<String> retryCodesConfigNames, ImmutableSet<String> retryParamsConfigNames) {
        ImmutableMap.Builder<String, GapicMethodConfig> methodConfigMapBuilder = ImmutableMap.builder();

        for (MethodConfigProto methodConfigProto : interfaceConfigProto.getMethodsList()) {
            Interface targetInterface = getTargetInterface(apiInterface,
                    methodConfigProto.getRerouteToGrpcInterface());
            Method method = targetInterface.lookupMethod(methodConfigProto.getName());
            if (method == null) {
                diagCollector.addDiag(
                        Diag.error(SimpleLocation.TOPLEVEL, "method not found: %s", methodConfigProto.getName()));
                continue;
            }
            GapicMethodConfig methodConfig = GapicMethodConfig.createMethodConfig(diagCollector, language,
                    methodConfigProto, method, messageConfigs, resourceNameConfigs, retryCodesConfigNames,
                    retryParamsConfigNames);
            if (methodConfig == null) {
                continue;
            }
            methodConfigMapBuilder.put(methodConfigProto.getName(), methodConfig);
        }

        if (diagCollector.getErrorCount() > 0) {
            return null;
        } else {
            return methodConfigMapBuilder.build();
        }
    }

    static <T> List<T> createMethodConfigs(ImmutableMap<String, T> methodConfigMap,
            InterfaceConfigProto interfaceConfigProto) {
        List<T> methodConfigs = new ArrayList<>();
        for (MethodConfigProto methodConfigProto : interfaceConfigProto.getMethodsList()) {
            methodConfigs.add(methodConfigMap.get(methodConfigProto.getName()));
        }
        return methodConfigs;
    }

    /** Returns the GapicMethodConfig for the given method. */
    @Override
    public GapicMethodConfig getMethodConfig(MethodModel method) {
        return getMethodConfig(method.getSimpleName());
    }

    /** Returns the GapicMethodConfig for the given method. */
    public GapicMethodConfig getMethodConfig(Method method) {
        return getMethodConfig(method.getSimpleName());
    }

    public GapicMethodConfig getMethodConfig(String methodSimpleName) {
        return getMethodConfigMap().get(methodSimpleName);
    }

    @Override
    public boolean hasDefaultServiceAddress() {
        return !getRequiredConstructorParams().contains(SERVICE_ADDRESS_PARAM);
    }

    @Override
    public boolean hasDefaultServiceScopes() {
        return !getRequiredConstructorParams().contains(SCOPES_PARAM);
    }

    @Override
    public boolean hasDefaultInstance() {
        return getRequiredConstructorParams().size() == 0;
    }

    /**
     * If rerouteToGrpcInterface is set, then looks up that interface and returns it, otherwise
     * returns the value of defaultInterface.
     */
    public static Interface getTargetInterface(Interface defaultInterface, String rerouteToGrpcInterface) {
        Interface targetInterface = defaultInterface;
        if (!Strings.isNullOrEmpty(rerouteToGrpcInterface)) {
            targetInterface = defaultInterface.getModel().getSymbolTable().lookupInterface(rerouteToGrpcInterface);
            if (targetInterface == null) {
                throw new IllegalArgumentException(
                        "reroute_to_grpc_interface not found: " + rerouteToGrpcInterface);
            }
        }
        return targetInterface;
    }

    /** Creates a list of fields that can be turned into IAM resources */
    private static ImmutableList<FieldModel> createIamResources(Model model, List<IamResourceProto> resources) {
        ImmutableList.Builder<FieldModel> fields = ImmutableList.builder();
        for (IamResourceProto resource : resources) {
            TypeRef type = model.getSymbolTable().lookupType(resource.getType());
            if (type == null) {
                throw new IllegalArgumentException("type not found: " + resource.getType());
            }
            if (!type.isMessage()) {
                throw new IllegalArgumentException("type must be a message: " + type);
            }
            Field field = type.getMessageType().lookupField(resource.getField());
            if (field == null) {
                throw new IllegalArgumentException(
                        String.format("type %s does not have field %s", resource.getType(), resource.getField()));
            }
            fields.add(new ProtoField(field));
        }
        return fields.build();
    }

    @Override
    public boolean hasPageStreamingMethods() {
        for (MethodConfig methodConfig : getMethodConfigs()) {
            if (methodConfig.isPageStreaming()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean hasBatchingMethods() {
        for (MethodConfig methodConfig : getMethodConfigs()) {
            if (methodConfig.isBatching()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean hasGrpcStreamingMethods() {
        for (MethodConfig methodConfig : getMethodConfigs()) {
            if (methodConfig.isGrpcStreaming()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean hasGrpcStreamingMethods(GrpcStreamingConfig.GrpcStreamingType streamingType) {
        for (GapicMethodConfig methodConfig : getMethodConfigs()) {
            if (methodConfig.isGrpcStreaming() && methodConfig.getGrpcStreamingType() == streamingType) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean hasLongRunningOperations() {
        for (MethodConfig methodConfig : getMethodConfigs()) {
            if (methodConfig.isLongRunningOperation()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean hasReroutedInterfaceMethods() {
        for (MethodConfig methodConfig : getMethodConfigs()) {
            if (!Strings.isNullOrEmpty(methodConfig.getRerouteToGrpcInterface())) {
                return true;
            }
        }
        return false;
    }
}