1 // Copyright 2020 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.google.api.generator.gapic.model; 16 17 import com.google.api.generator.engine.ast.TypeNode; 18 import com.google.auto.value.AutoValue; 19 import com.google.common.base.Splitter; 20 import com.google.common.base.Strings; 21 import com.google.common.collect.ImmutableList; 22 import com.google.common.collect.Iterables; 23 import java.util.List; 24 import javax.annotation.Nullable; 25 26 @AutoValue 27 public abstract class Service { name()28 public abstract String name(); 29 defaultHost()30 public abstract String defaultHost(); 31 oauthScopes()32 public abstract ImmutableList<String> oauthScopes(); 33 pakkage()34 public abstract String pakkage(); 35 protoPakkage()36 public abstract String protoPakkage(); 37 38 // For compatibility with other protoc-plugin code generators, e.g. gRPC. originalJavaPackage()39 public abstract String originalJavaPackage(); 40 41 // New Java class name as defined in gapic.yaml's language settings. overriddenName()42 public abstract String overriddenName(); 43 isDeprecated()44 public abstract boolean isDeprecated(); 45 methods()46 public abstract ImmutableList<Method> methods(); 47 48 @Nullable description()49 public abstract String description(); 50 hasDescription()51 public boolean hasDescription() { 52 return !Strings.isNullOrEmpty(description()); 53 } 54 apiShortName()55 public String apiShortName() { 56 if (!Strings.isNullOrEmpty(defaultHost())) { 57 return parseApiShortName(defaultHost()); 58 } 59 return ""; 60 } 61 apiVersion()62 public String apiVersion() { 63 if (!Strings.isNullOrEmpty(protoPakkage())) { 64 return parseApiVersion(protoPakkage()); 65 } 66 return ""; 67 } 68 operationPollingMethod()69 public Method operationPollingMethod() { 70 for (Method method : methods()) { 71 if (method.isOperationPollingMethod()) { 72 return method; 73 } 74 } 75 return null; 76 } 77 operationServiceStubType()78 public TypeNode operationServiceStubType() { 79 for (Method method : methods()) { 80 if (method.hasLro() && method.lro().operationServiceStubType() != null) { 81 // All methods within the same service must have the same operationServiceTypeName if 82 // present 83 return method.lro().operationServiceStubType(); 84 } 85 } 86 return null; 87 } 88 operationType()89 public TypeNode operationType() { 90 for (Method method : methods()) { 91 if (method.hasLro() && method.lro().operationServiceStubType() != null) { 92 return method.outputType(); 93 } 94 } 95 return null; 96 } 97 hasLroMethods()98 public boolean hasLroMethods() { 99 for (Method method : methods()) { 100 if (method.hasLro()) { 101 return true; 102 } 103 } 104 return false; 105 } 106 hasStandardLroMethods()107 public boolean hasStandardLroMethods() { 108 for (Method method : methods()) { 109 if (method.hasLro() && method.lro().operationServiceStubType() == null) { 110 return true; 111 } 112 } 113 return false; 114 } 115 116 /** 117 * Wrapper for hasAnyEnabledMethodsForTransport(Transport). Some invocations are called with 118 * `gRPC` which can't match with the correct Transport (GRPC) 119 * 120 * @param transportName String transport value 121 * @return boolean if service contains any enabled methods for a transport 122 */ hasAnyEnabledMethodsForTransport(String transportName)123 public boolean hasAnyEnabledMethodsForTransport(String transportName) { 124 return hasAnyEnabledMethodsForTransport(Transport.parse(transportName)); 125 } 126 127 /** 128 * Determines if a Service contains any methods that are both eligible and enabled for the 129 * Transport. GRPC+REST Transport is not supported as each transport's sub composers will invoke 130 * this method the specific transport (GRPC or REST) 131 * 132 * @param transport Expects either GRPC or REST Transport 133 * @return boolean if service contains any enabled methods for a transport 134 */ hasAnyEnabledMethodsForTransport(Transport transport)135 public boolean hasAnyEnabledMethodsForTransport(Transport transport) { 136 if (transport == Transport.GRPC_REST) { 137 throw new IllegalArgumentException( 138 String.format("Invalid Transport: %s. Expecting GRPC or REST", transport.name())); 139 } 140 return methods().stream().anyMatch(x -> x.isSupportedByTransport(transport)); 141 } 142 toBuilder()143 public abstract Builder toBuilder(); 144 builder()145 public static Builder builder() { 146 return new AutoValue_Service.Builder().setMethods(ImmutableList.of()).setIsDeprecated(false); 147 } 148 149 @AutoValue.Builder 150 public abstract static class Builder { setName(String name)151 public abstract Builder setName(String name); 152 setOverriddenName(String overriddenName)153 public abstract Builder setOverriddenName(String overriddenName); 154 setDefaultHost(String defaultHost)155 public abstract Builder setDefaultHost(String defaultHost); 156 setOauthScopes(List<String> oauthScopes)157 public abstract Builder setOauthScopes(List<String> oauthScopes); 158 setPakkage(String pakkage)159 public abstract Builder setPakkage(String pakkage); 160 setProtoPakkage(String pakkage)161 public abstract Builder setProtoPakkage(String pakkage); 162 setOriginalJavaPackage(String originalJavaPackage)163 public abstract Builder setOriginalJavaPackage(String originalJavaPackage); 164 setIsDeprecated(boolean isDeprecated)165 public abstract Builder setIsDeprecated(boolean isDeprecated); 166 setMethods(List<Method> methods)167 public abstract Builder setMethods(List<Method> methods); 168 setDescription(String description)169 public abstract Builder setDescription(String description); 170 build()171 public abstract Service build(); 172 } 173 parseApiVersion(String protoPackage)174 private static String parseApiVersion(String protoPackage) { 175 // parse protoPackage for apiVersion 176 String[] pakkage = protoPackage.split("\\."); 177 String apiVersion; 178 // e.g. v1, v2, v1beta1 179 if (pakkage[pakkage.length - 1].matches("v[0-9].*")) { 180 apiVersion = pakkage[pakkage.length - 1]; 181 } else { 182 apiVersion = ""; 183 } 184 return apiVersion; 185 } 186 187 // Parse defaultHost for apiShortName for the RegionTag. Need to account for regional default 188 // endpoints like 189 // "us-east1-pubsub.googleapis.com". parseApiShortName(String defaultHost)190 private static String parseApiShortName(String defaultHost) { 191 // If the defaultHost is of the format "**.googleapis.com", take the name before the first 192 // period. 193 String apiShortName = Iterables.getFirst(Splitter.on(".").split(defaultHost), defaultHost); 194 // If the defaultHost is of the format "**-**-**.googleapis.com", take the section before the 195 // first period and after the last dash to follow CSharp's implementation here: 196 // https://github.com/googleapis/gapic-generator-csharp/blob/main/Google.Api.Generator/Generation/ServiceDetails.cs#L70 197 apiShortName = Iterables.getLast(Splitter.on("-").split(apiShortName), defaultHost); 198 // `iam-meta-api` service is an exceptional case and is handled as a one-off 199 if (defaultHost.contains("iam-meta-api")) { 200 apiShortName = "iam"; 201 } 202 return apiShortName; 203 } 204 } 205