diff --git a/src/main/java/com/google/api/codegen/InterfaceListView.java b/src/main/java/com/google/api/codegen/InterfaceListView.java deleted file mode 100644 index 2ab47d1e5e..0000000000 --- a/src/main/java/com/google/api/codegen/InterfaceListView.java +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright 2016 Google Inc - * - * 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 - * - * http://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; - -import com.google.api.tools.framework.model.Interface; -import com.google.api.tools.framework.model.Model; - -import java.util.ArrayList; - -/** - * An interface-based view of model, consisting of a strategy for getting the interfaces of the - * model and returning them in a single iterable object. - */ -public class InterfaceListView implements InputElementView> { - - /** - * Gets the reachable interfaces of the model. - */ - @Override - public Iterable> getElementIterable(Model model) { - ArrayList interfaces = new ArrayList<>(); - for (Interface iface : model.getSymbolTable().getInterfaces()) { - if (iface.isReachable()) { - interfaces.add(iface); - } - } - ArrayList> result = new ArrayList<>(); - result.add(interfaces); - return result; - } -} diff --git a/src/main/java/com/google/api/codegen/ServiceConfig.java b/src/main/java/com/google/api/codegen/ServiceConfig.java index 1f27fefc7a..5cbb3407eb 100644 --- a/src/main/java/com/google/api/codegen/ServiceConfig.java +++ b/src/main/java/com/google/api/codegen/ServiceConfig.java @@ -20,9 +20,9 @@ import com.google.api.tools.framework.model.Interface; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.TreeSet; /** * Utility class that provides service configuration data from an Interface. @@ -50,7 +50,7 @@ public String getTitle(Interface service) { * Return a list of scopes for authentication. */ public Iterable getAuthScopes(Interface service) { - Set result = new HashSet<>(); + Set result = new TreeSet<>(); Service config = service.getModel().getServiceConfig(); Authentication auth = config.getAuthentication(); for (AuthenticationRule rule : auth.getRulesList()) { diff --git a/src/main/java/com/google/api/codegen/ServiceMessages.java b/src/main/java/com/google/api/codegen/ServiceMessages.java index 75f85d5b13..e76d1b4e05 100644 --- a/src/main/java/com/google/api/codegen/ServiceMessages.java +++ b/src/main/java/com/google/api/codegen/ServiceMessages.java @@ -33,6 +33,10 @@ public class ServiceMessages { * Returns true if the message is the empty message. */ public boolean isEmptyType(TypeRef type) { + return s_isEmptyType(type); + } + + public static boolean s_isEmptyType(TypeRef type) { return type.isMessage() && type.getMessageType().getFullName().equals(Empty.getDescriptor().getFullName()); } diff --git a/src/main/java/com/google/api/codegen/csharp/CSharpContextCommon.java b/src/main/java/com/google/api/codegen/csharp/CSharpContextCommon.java index ae59115d2a..ae5099d087 100644 --- a/src/main/java/com/google/api/codegen/csharp/CSharpContextCommon.java +++ b/src/main/java/com/google/api/codegen/csharp/CSharpContextCommon.java @@ -50,6 +50,7 @@ public String addImport(String namespace) { */ public Iterable getXmlDocLines(String text, String element) { // TODO(jonskeet): Convert markdown to XML documentation format. + // https://github.com/googleapis/toolkit/issues/331 List result = new ArrayList<>(); result.add("/// <" + element + ">"); for (String line : Splitter.on(String.format("%n")).split(text)) { @@ -65,6 +66,7 @@ public Iterable getXmlDocLines(String text, String element) { */ public Iterable getXmlParameterLines(String text, String parameterName) { // TODO(jonskeet): Convert markdown to XML documentation format. + // https://github.com/googleapis/toolkit/issues/331 List result = new ArrayList<>(); result.add("/// "); for (String line : Splitter.on(String.format("%n")).split(text)) { diff --git a/src/main/java/com/google/api/codegen/gapic/MainGapicProviderFactory.java b/src/main/java/com/google/api/codegen/gapic/MainGapicProviderFactory.java index a043e48358..bd08f66881 100644 --- a/src/main/java/com/google/api/codegen/gapic/MainGapicProviderFactory.java +++ b/src/main/java/com/google/api/codegen/gapic/MainGapicProviderFactory.java @@ -15,39 +15,38 @@ package com.google.api.codegen.gapic; import com.google.api.codegen.ApiConfig; -import com.google.api.codegen.clientconfig.ClientConfigGapicContext; -import com.google.api.codegen.InterfaceListView; import com.google.api.codegen.InterfaceView; import com.google.api.codegen.ProtoFileView; import com.google.api.codegen.SnippetSetRunner; +import com.google.api.codegen.clientconfig.ClientConfigGapicContext; import com.google.api.codegen.clientconfig.ClientConfigSnippetSetRunner; import com.google.api.codegen.csharp.CSharpCodePathMapper; import com.google.api.codegen.csharp.CSharpGapicContext; import com.google.api.codegen.csharp.CSharpSnippetSetRunner; import com.google.api.codegen.go.GoGapicContext; import com.google.api.codegen.go.GoSnippetSetRunner; -import com.google.api.codegen.java.JavaGapicContext; -import com.google.api.codegen.java.JavaIterableSnippetSetRunner; -import com.google.api.codegen.java.JavaSnippetSetRunner; import com.google.api.codegen.nodejs.NodeJSGapicContext; import com.google.api.codegen.nodejs.NodeJSSnippetSetRunner; -import com.google.api.codegen.php.PhpGapicContext; -import com.google.api.codegen.php.PhpSnippetSetRunner; import com.google.api.codegen.py.PythonGapicContext; import com.google.api.codegen.py.PythonInterfaceInitializer; import com.google.api.codegen.py.PythonProtoFileInitializer; import com.google.api.codegen.py.PythonSnippetSetRunner; +import com.google.api.codegen.rendering.CommonSnippetSetRunner; import com.google.api.codegen.ruby.RubyGapicContext; import com.google.api.codegen.ruby.RubySnippetSetRunner; +import com.google.api.codegen.transformer.java.JavaGapicSurfaceTransformer; +import com.google.api.codegen.transformer.php.PhpGapicSurfaceTransformer; +import com.google.api.codegen.util.CommonRenderingUtil; +import com.google.api.codegen.util.java.JavaRenderingUtil; import com.google.api.tools.framework.model.Interface; import com.google.api.tools.framework.model.Model; import com.google.api.tools.framework.model.ProtoFile; -import org.apache.commons.lang3.NotImplementedException; - import java.util.Arrays; import java.util.List; +import org.apache.commons.lang3.NotImplementedException; + /** * MainGapicProviderFactory creates GapicProvider instances based on an id. */ @@ -119,28 +118,14 @@ public static List> defaultCreate( .setShouldAppendPackage(true) .build(); GapicProvider mainProvider = - CommonGapicProvider.newBuilder() - .setModel(model) - .setView(new InterfaceView()) - .setContext(new JavaGapicContext(model, apiConfig)) - .setSnippetSetRunner( - new JavaSnippetSetRunner(SnippetSetRunner.SNIPPET_RESOURCE_ROOT)) - .setSnippetFileNames(Arrays.asList("java/main.snip", "java/settings.snip")) - .setCodePathMapper(javaPathMapper) - .build(); - GapicProvider packageInfoProvider = - CommonGapicProvider.>newBuilder() + ViewModelGapicProvider.newBuilder() .setModel(model) - .setView(new InterfaceListView()) - .setContext(new JavaGapicContext(model, apiConfig)) - .setSnippetSetRunner( - new JavaIterableSnippetSetRunner( - SnippetSetRunner.SNIPPET_RESOURCE_ROOT)) - .setSnippetFileNames(Arrays.asList("java/package-info.snip")) - .setCodePathMapper(javaPathMapper) + .setApiConfig(apiConfig) + .setSnippetSetRunner(new CommonSnippetSetRunner(new JavaRenderingUtil())) + .setModelToViewTransformer(new JavaGapicSurfaceTransformer(javaPathMapper)) .build(); - return Arrays.>asList(mainProvider, packageInfoProvider); + return Arrays.>asList(mainProvider); } else if (id.equals(NODEJS)) { GapicCodePathMapper nodeJSPathMapper = @@ -173,14 +158,11 @@ public static List> defaultCreate( GapicCodePathMapper phpPathMapper = CommonGapicCodePathMapper.newBuilder().setPrefix("src").build(); GapicProvider provider = - CommonGapicProvider.newBuilder() + ViewModelGapicProvider.newBuilder() .setModel(model) - .setView(new InterfaceView()) - .setContext(new PhpGapicContext(model, apiConfig)) - .setSnippetSetRunner( - new PhpSnippetSetRunner(SnippetSetRunner.SNIPPET_RESOURCE_ROOT)) - .setSnippetFileNames(Arrays.asList("php/main.snip")) - .setCodePathMapper(phpPathMapper) + .setApiConfig(apiConfig) + .setSnippetSetRunner(new CommonSnippetSetRunner(new CommonRenderingUtil())) + .setModelToViewTransformer(new PhpGapicSurfaceTransformer(apiConfig, phpPathMapper)) .build(); GapicCodePathMapper phpClientConfigPathMapper = diff --git a/src/main/java/com/google/api/codegen/gapic/ViewModelGapicProvider.java b/src/main/java/com/google/api/codegen/gapic/ViewModelGapicProvider.java new file mode 100644 index 0000000000..3e80395365 --- /dev/null +++ b/src/main/java/com/google/api/codegen/gapic/ViewModelGapicProvider.java @@ -0,0 +1,122 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.gapic; + +import com.google.api.codegen.ApiConfig; +import com.google.api.codegen.rendering.CommonSnippetSetRunner; +import com.google.api.codegen.transformer.ModelToViewTransformer; +import com.google.api.codegen.viewmodel.ViewModel; +import com.google.api.tools.framework.model.Interface; +import com.google.api.tools.framework.model.Model; +import com.google.api.tools.framework.model.stages.Merged; +import com.google.api.tools.framework.snippet.Doc; + +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +public class ViewModelGapicProvider implements GapicProvider { + private final Model model; + private final ApiConfig apiConfig; + private final CommonSnippetSetRunner snippetSetRunner; + private final ModelToViewTransformer modelToViewTransformer; + + private ViewModelGapicProvider( + Model model, + ApiConfig apiConfig, + CommonSnippetSetRunner snippetSetRunner, + ModelToViewTransformer modelToViewTransformer) { + this.model = model; + this.apiConfig = apiConfig; + this.snippetSetRunner = snippetSetRunner; + this.modelToViewTransformer = modelToViewTransformer; + } + + @Override + public List getSnippetFileNames() { + return modelToViewTransformer.getTemplateFileNames(); + } + + @Override + public Map generate() { + return generate(null); + } + + @Override + public Map generate(String snippetFileName) { + // Establish required stage for generation. + model.establishStage(Merged.KEY); + if (model.getDiagCollector().getErrorCount() > 0) { + return null; + } + + List surfaceDocs = modelToViewTransformer.transform(model, apiConfig); + if (model.getDiagCollector().getErrorCount() > 0) { + return null; + } + + Map docs = new TreeMap<>(); + for (ViewModel surfaceDoc : surfaceDocs) { + if (snippetFileName != null && !surfaceDoc.templateFileName().equals(snippetFileName)) { + continue; + } + Doc doc = snippetSetRunner.generate(surfaceDoc); + if (doc == null) { + // generation failed; failures are captured in the model. + continue; + } + docs.put(surfaceDoc.outputPath(), doc); + } + + return docs; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private Model model; + private ApiConfig apiConfig; + private CommonSnippetSetRunner snippetSetRunner; + private ModelToViewTransformer modelToViewTransformer; + + private Builder() {} + + public Builder setModel(Model model) { + this.model = model; + return this; + } + + public Builder setApiConfig(ApiConfig apiConfig) { + this.apiConfig = apiConfig; + return this; + } + + public Builder setSnippetSetRunner(CommonSnippetSetRunner snippetSetRunner) { + this.snippetSetRunner = snippetSetRunner; + return this; + } + + public Builder setModelToViewTransformer(ModelToViewTransformer modelToViewTransformer) { + this.modelToViewTransformer = modelToViewTransformer; + return this; + } + + public ViewModelGapicProvider build() { + return new ViewModelGapicProvider(model, apiConfig, snippetSetRunner, modelToViewTransformer); + } + } +} diff --git a/src/main/java/com/google/api/codegen/java/JavaContextCommon.java b/src/main/java/com/google/api/codegen/java/JavaContextCommon.java index fe8de9c9de..34d05da145 100644 --- a/src/main/java/com/google/api/codegen/java/JavaContextCommon.java +++ b/src/main/java/com/google/api/codegen/java/JavaContextCommon.java @@ -128,7 +128,8 @@ public Iterable getJavaDocLines(String text) { * firstLinePrefix. Markdown will be translated to javadoc. */ public Iterable getJavaDocLinesWithPrefix(String text, String firstLinePrefix) { - // TODO(wgg): convert markdown to javadoc + // TODO: convert markdown to javadoc + // https://github.com/googleapis/toolkit/issues/331 List result = new ArrayList<>(); String linePrefix = firstLinePrefix; text = JAVADOC_ESCAPER.escape(text); diff --git a/src/main/java/com/google/api/codegen/java/JavaDocConfig.java b/src/main/java/com/google/api/codegen/java/JavaDocConfig.java deleted file mode 100644 index e8f738f6ea..0000000000 --- a/src/main/java/com/google/api/codegen/java/JavaDocConfig.java +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2016 Google Inc - * - * 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 - * - * http://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.java; - -import com.google.api.codegen.DocConfig; -import com.google.api.codegen.metacode.InitCode; -import com.google.api.codegen.metacode.InputParameter; -import com.google.api.tools.framework.model.Field; -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; - -import javax.annotation.Nullable; - -/** - * Represents the Java documentation settings for an Api method. - */ -@AutoValue -abstract class JavaDocConfig extends DocConfig { - public static Builder newBuilder() { - return new AutoValue_JavaDocConfig.Builder(); - } - - public String getGenericAwareReturnType() { - String returnType = getReturnType(); - if (returnType == null || returnType.isEmpty()) { - return "Void"; - } else { - return returnType; - } - } - - public abstract boolean isPagedVariant(); - - public abstract boolean isCallableVariant(); - - @Nullable - public abstract Field getResourcesFieldForUnpagedListCallable(); - - public boolean isUnpagedListCallableVariant() { - return getResourcesFieldForUnpagedListCallable() != null; - } - - @AutoValue.Builder - abstract static class Builder extends DocConfig.Builder { - public abstract JavaDocConfig build(); - - public abstract Builder setApiName(String serviceName); - - public abstract Builder setMethodName(String methodName); - - public abstract Builder setReturnType(String returnType); - - public abstract Builder setInitCode(InitCode initCode); - - public abstract Builder setParams(ImmutableList params); - - public abstract Builder setPagedVariant(boolean paged); - - public abstract Builder setCallableVariant(boolean callable); - - public abstract Builder setResourcesFieldForUnpagedListCallable(Field field); - - @Override - protected Builder setInitCodeProxy(InitCode initCode) { - return setInitCode(initCode); - } - - @Override - protected Builder setParamsProxy(ImmutableList params) { - return setParams(params); - } - } -} diff --git a/src/main/java/com/google/api/codegen/java/JavaGapicContext.java b/src/main/java/com/google/api/codegen/java/JavaGapicContext.java deleted file mode 100644 index d026fb36d7..0000000000 --- a/src/main/java/com/google/api/codegen/java/JavaGapicContext.java +++ /dev/null @@ -1,367 +0,0 @@ -/* Copyright 2016 Google Inc - * - * 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 - * - * http://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.java; - -import com.google.api.codegen.ApiConfig; -import com.google.api.codegen.GapicContext; -import com.google.api.codegen.MethodConfig; -import com.google.api.tools.framework.model.Field; -import com.google.api.tools.framework.model.FieldSelector; -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.ProtoElement; -import com.google.api.tools.framework.model.ProtoFile; -import com.google.api.tools.framework.model.TypeRef; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.io.Files; -import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type; - -import java.io.File; -import java.util.Arrays; - -/** - * A GapicContext specialized for Java. - */ -public class JavaGapicContext extends GapicContext implements JavaContext { - - /** - * The package prefix protoc uses if no java package option was provided. - */ - private static final String DEFAULT_JAVA_PACKAGE_PREFIX = "com.google.protos"; - - /** - * A map from primitive types in proto to Java counterparts. - */ - private static final ImmutableMap PRIMITIVE_TYPE_MAP = - ImmutableMap.builder() - .put(Type.TYPE_BOOL, "boolean") - .put(Type.TYPE_DOUBLE, "double") - .put(Type.TYPE_FLOAT, "float") - .put(Type.TYPE_INT64, "long") - .put(Type.TYPE_UINT64, "long") - .put(Type.TYPE_SINT64, "long") - .put(Type.TYPE_FIXED64, "long") - .put(Type.TYPE_SFIXED64, "long") - .put(Type.TYPE_INT32, "int") - .put(Type.TYPE_UINT32, "int") - .put(Type.TYPE_SINT32, "int") - .put(Type.TYPE_FIXED32, "int") - .put(Type.TYPE_SFIXED32, "int") - .put(Type.TYPE_STRING, "java.lang.String") - .put(Type.TYPE_BYTES, "com.google.protobuf.ByteString") - .build(); - - /** - * A map from primitive types in proto to zero value in Java - */ - private static final ImmutableMap PRIMITIVE_ZERO_VALUE = - ImmutableMap.builder() - .put(Type.TYPE_BOOL, "false") - .put(Type.TYPE_DOUBLE, "0.0") - .put(Type.TYPE_FLOAT, "0.0F") - .put(Type.TYPE_INT64, "0L") - .put(Type.TYPE_UINT64, "0L") - .put(Type.TYPE_SINT64, "0L") - .put(Type.TYPE_FIXED64, "0L") - .put(Type.TYPE_SFIXED64, "0L") - .put(Type.TYPE_INT32, "0") - .put(Type.TYPE_UINT32, "0") - .put(Type.TYPE_SINT32, "0") - .put(Type.TYPE_FIXED32, "0") - .put(Type.TYPE_SFIXED32, "0") - .put(Type.TYPE_STRING, "\"\"") - .put(Type.TYPE_BYTES, "ByteString.copyFromUtf8(\"\")") - .build(); - - private JavaContextCommon javaCommon; - - public JavaGapicContext(Model model, ApiConfig apiConfig) { - super(model, apiConfig); - } - - @Override - public void resetState(JavaContextCommon javaCommon) { - this.javaCommon = javaCommon; - } - - public JavaContextCommon java() { - return javaCommon; - } - - // Snippet Helpers - // =============== - - /** - * Takes a fully-qualified type name and returns its simple name, and also saves the type in the - * import list. - */ - public String getTypeName(String typeName) { - int lastDotIndex = typeName.lastIndexOf('.'); - if (lastDotIndex < 0) { - throw new IllegalArgumentException("expected fully qualified name"); - } - String shortTypeName = typeName.substring(lastDotIndex + 1); - return javaCommon.getMinimallyQualifiedName(typeName, shortTypeName); - } - - /** - * Adds the given type name to the import list. Returns an empty string so that the output is not - * affected in snippets. - */ - public String addImport(String typeName) { - // used for its side effect of adding the type to the import list if the short name - // hasn't been imported yet - getTypeName(typeName); - return ""; - } - - /** - * Gets the java package for the given proto file. - */ - public String getJavaPackage(ProtoFile file) { - String packageName = file.getProto().getOptions().getJavaPackage(); - if (Strings.isNullOrEmpty(packageName)) { - return DEFAULT_JAVA_PACKAGE_PREFIX + "." + file.getFullName(); - } - return packageName; - } - - /** - * Gets the name of the class which is the grpc container for this service interface. - */ - public String getGrpcName(Interface service) { - String fullName = - String.format("%s.%sGrpc", getJavaPackage(service.getFile()), service.getSimpleName()); - return getTypeName(fullName); - } - - /** - * Given a TypeRef, returns the return statement for that type. Specifically, this will return an - * empty string for the empty type (we don't want a return statement for void). - */ - public String methodReturnStatement(TypeRef type) { - if (messages().isEmptyType(type)) { - return ""; - } else { - return "return "; - } - } - - /** - * Given a TypeRef, returns the String form of the type to be used as a return value. Special - * case: this will return "void" for the Empty return type. - */ - public String methodReturnTypeName(TypeRef type) { - if (messages().isEmptyType(type)) { - return "void"; - } else { - return typeName(type); - } - } - - /** - * Returns the Java representation of a reference to a type. - */ - public String typeName(TypeRef type) { - if (type.isMap()) { - String mapTypeName = getTypeName("java.util.Map"); - return String.format( - "%s<%s, %s>", - mapTypeName, - basicTypeNameBoxed(type.getMapKeyField().getType()), - basicTypeNameBoxed(type.getMapValueField().getType())); - } else if (type.isRepeated()) { - String listTypeName = getTypeName("java.util.List"); - return String.format("%s<%s>", listTypeName, basicTypeNameBoxed(type)); - } else { - return basicTypeName(type); - } - } - - /** - * Returns the Java representation of a zero value for that type, to be used in code sample doc. - * - * Parametric types may use the diamond operator, since the return value will be used only in - * initialization. - */ - public String zeroValue(TypeRef type) { - // Don't call getTypeName; we don't need to import these. - if (type.isMap()) { - return "new HashMap<>()"; - } - if (type.isRepeated()) { - return "new ArrayList<>()"; - } - if (PRIMITIVE_ZERO_VALUE.containsKey(type.getKind())) { - return PRIMITIVE_ZERO_VALUE.get(type.getKind()); - } - if (type.isMessage()) { - return typeName(type) + ".newBuilder().build()"; - } - return "null"; - } - - public String returnTypeOrEmpty(TypeRef returnType) { - return messages().isEmptyType(returnType) ? "" : typeName(returnType); - } - - /** - * Returns the Java representation of a type, without cardinality, in boxed form. - */ - public String basicTypeNameBoxed(TypeRef type) { - return javaCommon.boxedTypeName(basicTypeName(type)); - } - - /** - * Returns the Java representation of a type, without cardinality. If the type is a Java - * primitive, basicTypeName returns it in unboxed form. - */ - public String basicTypeName(TypeRef type) { - String result = PRIMITIVE_TYPE_MAP.get(type.getKind()); - if (result != null) { - if (result.contains(".")) { - // Fully qualified type name, use regular type name resolver. Can skip boxing logic - // because those types are already boxed. - return getTypeName(result); - } - return result; - } - switch (type.getKind()) { - case TYPE_MESSAGE: - return getTypeName(type.getMessageType()); - case TYPE_ENUM: - return getTypeName(type.getEnumType()); - default: - throw new IllegalArgumentException("unknown type kind: " + type.getKind()); - } - } - - /** - * Gets the full name of the message or enum type in Java. - */ - public String getTypeName(ProtoElement elem) { - // Construct the full name in Java - String name = getJavaPackage(elem.getFile()); - if (!elem.getFile().getProto().getOptions().getJavaMultipleFiles()) { - String outerClassName = elem.getFile().getProto().getOptions().getJavaOuterClassname(); - if (outerClassName.isEmpty()) { - outerClassName = getFileClassName(elem.getFile()); - } - name = name + "." + outerClassName; - } - String shortName = elem.getFullName().substring(elem.getFile().getFullName().length() + 1); - name = name + "." + shortName; - - return javaCommon.getMinimallyQualifiedName(name, shortName); - } - - /** - * Gets the class name for the given proto file. - */ - private String getFileClassName(ProtoFile file) { - String baseName = Files.getNameWithoutExtension(new File(file.getSimpleName()).getName()); - return lowerUnderscoreToUpperCamel(baseName); - } - - public String defaultTokenValue(Field field) { - if (field.getType().getKind().equals(Type.TYPE_STRING)) { - return "\"\""; - } else if (field.getType().getKind().equals(Type.TYPE_BYTES)) { - String byteStringTypeName = getTypeName("com.google.protobuf.ByteString"); - return byteStringTypeName + ".EMPTY"; - } else { - throw new IllegalArgumentException( - String.format( - "Unsupported type for field %s - found %s, " - + "but expected TYPE_STRING or TYPE_BYTES", - field.getFullName(), - field.getType().getKind())); - } - } - - // Workaround for the fact that quotes can't be used in a snippet @join - public String partitionKeyCode(ImmutableList discriminatorFields) { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < discriminatorFields.size(); i++) { - if (i > 0) { - buf.append(" + \"|\" + "); - } - String simpleName = discriminatorFields.get(i).getLastField().getSimpleName(); - buf.append("request.get" + lowerUnderscoreToUpperCamel(simpleName) + "()"); - } - return buf.toString(); - } - - public Method getFirstFlattenedMethod(Interface service) { - for (Method method : service.getMethods()) { - MethodConfig methodConfig = - getApiConfig().getInterfaceConfig(service).getMethodConfig(method); - if (methodConfig.isFlattening()) { - return method; - } - } - throw new RuntimeException("No flattened methods available."); - } - - public String getTitle() { - return getModel().getServiceConfig().getTitle(); - } - - public String getMultilineHeading(String heading) { - final char[] array = new char[heading.length()]; - Arrays.fill(array, '='); - String eqsString = new String(array); - return String.format("%s\n%s\n%s", eqsString, heading, eqsString); - } - - public JavaDocConfig.Builder newJavaDocConfigBuilder() { - return JavaDocConfig.newBuilder(); - } - - /** - * Get a Java formatted primitive value, given a primitive type and a string representation of - * that value. The value must be a valid example of that type. Values of type Bool must be either - * the string 'true' or 'false' (other capitalizations are permitted). - */ - public String renderPrimitiveValue(TypeRef type, String value) { - Type primitiveType = type.getKind(); - if (!PRIMITIVE_TYPE_MAP.containsKey(primitiveType)) { - throw new IllegalArgumentException( - "Initial values are only supported for primitive types, got type " - + type - + ", with value " - + value); - } - switch (primitiveType) { - case TYPE_BOOL: - return value.toLowerCase(); - case TYPE_FLOAT: - return value + "F"; - case TYPE_INT64: - case TYPE_UINT64: - return value + "L"; - case TYPE_STRING: - return "\"" + value + "\""; - case TYPE_BYTES: - return "ByteString.copyFromUtf8(\"" + value + "\")"; - default: - // Types that do not need to be modified (e.g. TYPE_INT32) are handled here - return value; - } - } -} diff --git a/src/main/java/com/google/api/codegen/java/JavaIterableSnippetSetRunner.java b/src/main/java/com/google/api/codegen/java/JavaIterableSnippetSetRunner.java deleted file mode 100644 index acb39dac90..0000000000 --- a/src/main/java/com/google/api/codegen/java/JavaIterableSnippetSetRunner.java +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright 2016 Google Inc - * - * 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 - * - * http://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.java; - -import com.google.api.codegen.CodegenContext; -import com.google.api.codegen.GeneratedResult; -import com.google.api.codegen.SnippetSetRunner; -import com.google.api.tools.framework.snippet.Doc; -import com.google.api.tools.framework.snippet.SnippetSet; -import com.google.common.collect.ImmutableMap; - -import java.util.ArrayList; -import java.util.List; - -/** - * A JavaProvider provides general Java code generation logic that is agnostic to the use case - * (e.g. Gapic vs Discovery). Behavior that is specific to a use case is provided through a - * subclass of JavaContext. - */ -public class JavaIterableSnippetSetRunner - implements SnippetSetRunner.Generator> { - - private final String resourceRoot; - - public JavaIterableSnippetSetRunner(String resourceRoot) { - this.resourceRoot = resourceRoot; - } - - @Override - @SuppressWarnings("unchecked") - public GeneratedResult generate( - Iterable elementList, String snippetFileName, CodegenContext context) { - JavaIterableSnippetSet snippets = - SnippetSet.createSnippetInterface( - JavaIterableSnippetSet.class, - resourceRoot, - snippetFileName, - ImmutableMap.of("context", context)); - - String outputFilename = snippets.generateFilename().prettyPrint(); - JavaContextCommon javaContextCommon = new JavaContextCommon(); - - // TODO don't depend on a cast here - JavaContext javaContext = (JavaContext) context; - javaContext.resetState(javaContextCommon); - - List fragmentList = new ArrayList<>(); - for (ElementT element : elementList) { - fragmentList.add(snippets.generateFragment(element)); - } - - // Generate result. - Doc result = snippets.generateDocument(fragmentList); - return GeneratedResult.create(result, outputFilename); - } -} diff --git a/src/main/java/com/google/api/codegen/java/JavaSnippetSet.java b/src/main/java/com/google/api/codegen/java/JavaSnippetSet.java index 17e20dde73..e23020c5ca 100644 --- a/src/main/java/com/google/api/codegen/java/JavaSnippetSet.java +++ b/src/main/java/com/google/api/codegen/java/JavaSnippetSet.java @@ -38,9 +38,4 @@ interface JavaSnippetSet { * to be imported. */ Doc generateClass(Element element, Doc body, Iterable imports); - - /** - * Generate the example snippet for a method. - */ - Doc generateMethodSampleCode(JavaDocConfig config); } diff --git a/src/main/java/com/google/api/codegen/metacode/FieldSetting.java b/src/main/java/com/google/api/codegen/metacode/FieldSetting.java index 156b83b59a..0a91099091 100644 --- a/src/main/java/com/google/api/codegen/metacode/FieldSetting.java +++ b/src/main/java/com/google/api/codegen/metacode/FieldSetting.java @@ -14,6 +14,7 @@ */ package com.google.api.codegen.metacode; +import com.google.api.codegen.util.Name; import com.google.api.tools.framework.model.TypeRef; import com.google.auto.value.AutoValue; @@ -25,7 +26,7 @@ public abstract class FieldSetting { public static FieldSetting create( - TypeRef type, String fieldName, String identifier, InitValueConfig initValueConfig) { + TypeRef type, Name fieldName, Name identifier, InitValueConfig initValueConfig) { return new AutoValue_FieldSetting(type, fieldName, identifier, initValueConfig); } @@ -37,12 +38,12 @@ public static FieldSetting create( /** * Returns the name of the field in the containing structure. */ - public abstract String getFieldName(); + public abstract Name getFieldName(); /** * Returns the name of the identifier being set on the field. */ - public abstract String getIdentifier(); + public abstract Name getIdentifier(); /** * Returns the InitValueConfig for the original identifier. diff --git a/src/main/java/com/google/api/codegen/metacode/InitCodeGenerator.java b/src/main/java/com/google/api/codegen/metacode/InitCodeGenerator.java index 9acee0ecb8..278fc3ae54 100644 --- a/src/main/java/com/google/api/codegen/metacode/InitCodeGenerator.java +++ b/src/main/java/com/google/api/codegen/metacode/InitCodeGenerator.java @@ -14,6 +14,7 @@ */ package com.google.api.codegen.metacode; +import com.google.api.codegen.util.Name; import com.google.api.tools.framework.model.Field; import com.google.api.tools.framework.model.Method; import com.google.api.tools.framework.model.TypeRef; @@ -44,12 +45,12 @@ public class InitCodeGenerator { public InitCode generateRequestObjectInitCode( Method method, Map initFieldStructure) { InitCodeLine lastLine = - generateSampleCodeInit("request", method.getInputType(), initFieldStructure); + generateSampleCodeInit(Name.from("request"), method.getInputType(), initFieldStructure); initLineSpecs.add(lastLine); FieldSetting requestField = FieldSetting.create( method.getInputType(), - "request", + Name.from("request"), lastLine.getIdentifier(), lastLine.getInitValueConfig()); List outputFields = Arrays.asList(requestField); @@ -73,7 +74,8 @@ public InitCode generateRequestFieldInitCode( } } - InitCodeLine lastLine = generateSampleCodeInit("request", method.getInputType(), filteredInit); + InitCodeLine lastLine = + generateSampleCodeInit(Name.from("request"), method.getInputType(), filteredInit); if (!(lastLine instanceof StructureInitCodeLine)) { throw new IllegalArgumentException( "Expected method request to be a message, found " + lastLine.getClass().getName()); @@ -82,18 +84,18 @@ public InitCode generateRequestFieldInitCode( return InitCode.create(initLineSpecs, requestInitCodeLine.getFieldSettings()); } - private String getNewSymbol(String desiredName) { - String actualName = desiredName; + private Name getNewSymbol(Name desiredName) { + Name actualName = desiredName; int i = 2; - while (symbolTable.contains(actualName)) { - actualName = desiredName + i; + while (symbolTable.contains(actualName.toLowerUnderscore())) { + actualName = desiredName.join(Integer.toString(i)); } - symbolTable.add(actualName); + symbolTable.add(actualName.toLowerUnderscore()); return actualName; } private InitCodeLine generateSampleCodeInitStructure( - String suggestedName, TypeRef typeRef, Map initFieldMap) { + Name suggestedName, TypeRef typeRef, Map initFieldMap) { List fieldSettings = new ArrayList<>(); for (Field field : typeRef.getMessageType().getFields()) { Object thisFieldInitStructure = initFieldMap.get(field.getSimpleName()); @@ -102,13 +104,14 @@ private InitCodeLine generateSampleCodeInitStructure( } InitCodeLine subFieldInit = - generateSampleCodeInit(field.getSimpleName(), field.getType(), thisFieldInitStructure); + generateSampleCodeInit( + Name.from(field.getSimpleName()), field.getType(), thisFieldInitStructure); initLineSpecs.add(subFieldInit); FieldSetting fieldSetting = FieldSetting.create( field.getType(), - field.getSimpleName(), + Name.from(field.getSimpleName()), subFieldInit.getIdentifier(), subFieldInit.getInitValueConfig()); fieldSettings.add(fieldSetting); @@ -119,15 +122,15 @@ private InitCodeLine generateSampleCodeInitStructure( // get a new symbol for this object after subfields, in order to preserve // numerical ordering in the case of conflicts - String identifier = getNewSymbol(suggestedName); + Name identifier = getNewSymbol(suggestedName); return StructureInitCodeLine.create(typeRef, identifier, fieldSettings); } private InitCodeLine generateSampleCodeInitList( - String suggestedName, TypeRef typeRef, List thisFieldInitList) { - List elementIdentifiers = new ArrayList<>(); + Name suggestedName, TypeRef typeRef, List thisFieldInitList) { + List elementIdentifiers = new ArrayList<>(); for (Object elementInitStructure : thisFieldInitList) { - String suggestedElementName = suggestedName + "_element"; + Name suggestedElementName = suggestedName.join("element"); // Using the Optional cardinality replaces the Repeated cardinality TypeRef elementType = typeRef.makeOptional(); InitCodeLine subFieldInit = @@ -139,15 +142,15 @@ private InitCodeLine generateSampleCodeInitList( // get a new symbol for this object after elements, in order to preserve // numerical ordering in the case of conflicts - String identifier = getNewSymbol(suggestedName); + Name identifier = getNewSymbol(suggestedName); return ListInitCodeLine.create(typeRef, identifier, elementIdentifiers); } private InitCodeLine generateSampleCodeInitMap( - String suggestedName, TypeRef typeRef, Map thisFieldInitMap) { + Name suggestedName, TypeRef typeRef, Map thisFieldInitMap) { TypeRef keyTypeRef = typeRef.getMapKeyField().getType(); TypeRef elementType = typeRef.getMapValueField().getType(); - Map elementIdentifierMap = new HashMap(); + Map elementIdentifierMap = new HashMap<>(); for (String keyString : thisFieldInitMap.keySet()) { String validatedKeyString = validateValue(keyTypeRef, keyString); if (validatedKeyString == null) { @@ -163,7 +166,7 @@ private InitCodeLine generateSampleCodeInitMap( } Object elementInitStructure = thisFieldInitMap.get(keyString); - String suggestedElementName = suggestedName + "_item"; + Name suggestedElementName = suggestedName.join("item"); InitCodeLine subFieldInit = generateSampleCodeInit(suggestedElementName, elementType, elementInitStructure); initLineSpecs.add(subFieldInit); @@ -173,19 +176,19 @@ private InitCodeLine generateSampleCodeInitMap( // get a new symbol for this object after elements, in order to preserve // numerical ordering in the case of conflicts - String identifier = getNewSymbol(suggestedName); + Name identifier = getNewSymbol(suggestedName); return MapInitCodeLine.create( keyTypeRef, elementType, typeRef, identifier, elementIdentifierMap); } private InitCodeLine generateSampleCodeInit( - String suggestedName, TypeRef typeRef, Object initFieldStructure) { + Name suggestedName, TypeRef typeRef, Object initFieldStructure) { // No matter what the type in the model is, we want to stop here, because we // have reached the end of initFieldStructure. At codegen time, we will // generate the zero value for the type. if (initFieldStructure instanceof InitValueConfig) { InitValueConfig initValueConfig = (InitValueConfig) initFieldStructure; - String identifier = getNewSymbol(suggestedName); + Name identifier = getNewSymbol(suggestedName); if (initValueConfig.hasInitialValue()) { String validatedValue = validateValue(typeRef, initValueConfig.getInitialValue()); if (validatedValue == null) { diff --git a/src/main/java/com/google/api/codegen/metacode/InitCodeLine.java b/src/main/java/com/google/api/codegen/metacode/InitCodeLine.java index da72215e0c..07229b888a 100644 --- a/src/main/java/com/google/api/codegen/metacode/InitCodeLine.java +++ b/src/main/java/com/google/api/codegen/metacode/InitCodeLine.java @@ -14,11 +14,13 @@ */ package com.google.api.codegen.metacode; +import com.google.api.codegen.util.Name; + /** * InitCodeLine represents the creation of a variable with an initialized value. */ public interface InitCodeLine { - public String getIdentifier(); + public Name getIdentifier(); public InitValueConfig getInitValueConfig(); diff --git a/src/main/java/com/google/api/codegen/metacode/ListInitCodeLine.java b/src/main/java/com/google/api/codegen/metacode/ListInitCodeLine.java index 6db93c38b3..69d27b5445 100644 --- a/src/main/java/com/google/api/codegen/metacode/ListInitCodeLine.java +++ b/src/main/java/com/google/api/codegen/metacode/ListInitCodeLine.java @@ -14,6 +14,7 @@ */ package com.google.api.codegen.metacode; +import com.google.api.codegen.util.Name; import com.google.api.tools.framework.model.TypeRef; import com.google.auto.value.AutoValue; @@ -27,16 +28,16 @@ public abstract class ListInitCodeLine implements InitCodeLine { public static ListInitCodeLine create( - TypeRef elementType, String identifier, List elementIdentifiers) { + TypeRef elementType, Name identifier, List elementIdentifiers) { return new AutoValue_ListInitCodeLine(elementType, identifier, elementIdentifiers); } public abstract TypeRef getElementType(); @Override - public abstract String getIdentifier(); + public abstract Name getIdentifier(); - public abstract List getElementIdentifiers(); + public abstract List getElementIdentifiers(); @Override public InitCodeLineType getLineType() { diff --git a/src/main/java/com/google/api/codegen/metacode/MapInitCodeLine.java b/src/main/java/com/google/api/codegen/metacode/MapInitCodeLine.java index 338c989001..6083e2de5a 100644 --- a/src/main/java/com/google/api/codegen/metacode/MapInitCodeLine.java +++ b/src/main/java/com/google/api/codegen/metacode/MapInitCodeLine.java @@ -14,6 +14,7 @@ */ package com.google.api.codegen.metacode; +import com.google.api.codegen.util.Name; import com.google.api.tools.framework.model.TypeRef; import com.google.auto.value.AutoValue; @@ -30,8 +31,8 @@ public static MapInitCodeLine create( TypeRef keyType, TypeRef valueType, TypeRef elementType, - String identifier, - Map elementIdentifierMap) { + Name identifier, + Map elementIdentifierMap) { return new AutoValue_MapInitCodeLine( keyType, valueType, elementType, identifier, elementIdentifierMap); } @@ -43,15 +44,15 @@ public static MapInitCodeLine create( public abstract TypeRef getElementType(); @Override - public abstract String getIdentifier(); + public abstract Name getIdentifier(); - public abstract Map getElementIdentifierMap(); + public abstract Map getElementIdentifierMap(); public Iterable getElementIdentifierKeys() { return getElementIdentifierMap().keySet(); } - public String getElementIdentifierValue(String key) { + public Name getElementIdentifierValue(String key) { return getElementIdentifierMap().get(key); } diff --git a/src/main/java/com/google/api/codegen/metacode/SimpleInitCodeLine.java b/src/main/java/com/google/api/codegen/metacode/SimpleInitCodeLine.java index 9a0fa16f0e..562dba9ec9 100644 --- a/src/main/java/com/google/api/codegen/metacode/SimpleInitCodeLine.java +++ b/src/main/java/com/google/api/codegen/metacode/SimpleInitCodeLine.java @@ -14,6 +14,7 @@ */ package com.google.api.codegen.metacode; +import com.google.api.codegen.util.Name; import com.google.api.tools.framework.model.TypeRef; import com.google.auto.value.AutoValue; @@ -25,14 +26,14 @@ public abstract class SimpleInitCodeLine implements InitCodeLine { public static SimpleInitCodeLine create( - TypeRef type, String identifier, InitValueConfig initValueConfig) { + TypeRef type, Name identifier, InitValueConfig initValueConfig) { return new AutoValue_SimpleInitCodeLine(type, identifier, initValueConfig); } public abstract TypeRef getType(); @Override - public abstract String getIdentifier(); + public abstract Name getIdentifier(); @Override public abstract InitValueConfig getInitValueConfig(); diff --git a/src/main/java/com/google/api/codegen/metacode/StructureInitCodeLine.java b/src/main/java/com/google/api/codegen/metacode/StructureInitCodeLine.java index 9fda43d0b6..42b1f08f65 100644 --- a/src/main/java/com/google/api/codegen/metacode/StructureInitCodeLine.java +++ b/src/main/java/com/google/api/codegen/metacode/StructureInitCodeLine.java @@ -14,6 +14,7 @@ */ package com.google.api.codegen.metacode; +import com.google.api.codegen.util.Name; import com.google.api.tools.framework.model.TypeRef; import com.google.auto.value.AutoValue; @@ -27,14 +28,14 @@ public abstract class StructureInitCodeLine implements InitCodeLine { public static StructureInitCodeLine create( - TypeRef type, String identifier, List fieldSettings) { + TypeRef type, Name identifier, List fieldSettings) { return new AutoValue_StructureInitCodeLine(type, identifier, fieldSettings); } public abstract TypeRef getType(); @Override - public abstract String getIdentifier(); + public abstract Name getIdentifier(); public abstract List getFieldSettings(); diff --git a/src/main/java/com/google/api/codegen/php/PhpContext.java b/src/main/java/com/google/api/codegen/php/PhpContext.java index e9462f4729..ec2bf2266c 100644 --- a/src/main/java/com/google/api/codegen/php/PhpContext.java +++ b/src/main/java/com/google/api/codegen/php/PhpContext.java @@ -14,9 +14,11 @@ */ package com.google.api.codegen.php; +import com.google.api.codegen.util.php.PhpTypeTable; + /** * A PhpContext provides functionality specific to a context in PHP. */ public interface PhpContext { - void resetState(PhpContextCommon phpCommon); + void resetState(PhpTypeTable phpTypeTable); } diff --git a/src/main/java/com/google/api/codegen/php/PhpContextCommon.java b/src/main/java/com/google/api/codegen/php/PhpContextCommon.java deleted file mode 100644 index 1a489182f9..0000000000 --- a/src/main/java/com/google/api/codegen/php/PhpContextCommon.java +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright 2016 Google Inc - * - * 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 - * - * http://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.php; - -import com.google.common.base.Splitter; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class PhpContextCommon { - - /** - * A bi-map from full names to short names indicating the import map. - */ - private final BiMap imports = HashBiMap.create(); - - public String getMinimallyQualifiedName(String fullName, String shortName) { - // Derive a short name if possible - if (imports.containsKey(fullName)) { - // Short name already there. - return imports.get(fullName); - } - if (imports.containsValue(shortName)) { - // Short name clashes, use long name. - return fullName; - } - imports.put(fullName, shortName); - return shortName; - } - - public List getImports() { - // Clean up the imports. - List cleanedImports = new ArrayList<>(); - for (String imported : imports.keySet()) { - cleanedImports.add(imported); - } - Collections.sort(cleanedImports); - return cleanedImports; - } - - public boolean hasImports() { - return !getImports().isEmpty(); - } - - public Iterable getDocLines(String text) { - return getDocLinesWithPrefix(text, ""); - } - - public Iterable getDocLinesWithPrefix(String text, String firstLinePrefix) { - return getDocLinesWithPrefixes(text, firstLinePrefix, ""); - } - - public Iterable getDocLinesWithPrefixes( - String text, String firstLinePrefix, String remainderPrefix) { - // TODO: convert markdown to phpDoc - List result = new ArrayList<>(); - boolean onFirstLine = true; - for (String line : Splitter.on(String.format("%n")).split(text)) { - String linePrefix = onFirstLine ? firstLinePrefix : remainderPrefix; - onFirstLine = false; - result.add(" * " + linePrefix + line); - } - return result; - } -} diff --git a/src/main/java/com/google/api/codegen/php/PhpDiscoveryContext.java b/src/main/java/com/google/api/codegen/php/PhpDiscoveryContext.java index b86e94221f..ba7d179af9 100644 --- a/src/main/java/com/google/api/codegen/php/PhpDiscoveryContext.java +++ b/src/main/java/com/google/api/codegen/php/PhpDiscoveryContext.java @@ -17,6 +17,7 @@ import com.google.api.Service; import com.google.api.codegen.ApiaryConfig; import com.google.api.codegen.DiscoveryContext; +import com.google.api.codegen.util.php.PhpTypeTable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.protobuf.Field; @@ -32,7 +33,7 @@ public class PhpDiscoveryContext extends DiscoveryContext implements PhpContext private static final String GOOGLE_SERVICE_PREFIX = "Google_Service_"; - private PhpContextCommon phpCommon; + private PhpTypeTable phpTypeTable; /** * A map from inferred API package names to renamed counterparts in PHP client libraries. @@ -89,12 +90,12 @@ public PhpDiscoveryContext(Service service, ApiaryConfig apiaryConfig) { } @Override - public void resetState(PhpContextCommon phpCommon) { - this.phpCommon = phpCommon; + public void resetState(PhpTypeTable phpTypeTable) { + this.phpTypeTable = phpTypeTable; } - public PhpContextCommon php() { - return this.phpCommon; + public PhpTypeTable php() { + return this.phpTypeTable; } // Snippet Helpers diff --git a/src/main/java/com/google/api/codegen/php/PhpDocConfig.java b/src/main/java/com/google/api/codegen/php/PhpDocConfig.java deleted file mode 100644 index 1f2732609b..0000000000 --- a/src/main/java/com/google/api/codegen/php/PhpDocConfig.java +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright 2016 Google Inc - * - * 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 - * - * http://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.php; - -import com.google.api.codegen.DocConfig; -import com.google.api.codegen.metacode.InitCode; -import com.google.api.codegen.metacode.InputParameter; -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; - -import javax.annotation.Nullable; - -/** - * Represents the Php documentation settings for an Api method. - */ -@AutoValue -abstract class PhpDocConfig extends DocConfig { - public static PhpDocConfig.Builder newBuilder() { - return new AutoValue_PhpDocConfig.Builder(); - } - - public abstract boolean isPagedVariant(); - - @Override - @Nullable - public abstract ImmutableList getParams(); - - @AutoValue.Builder - abstract static class Builder extends DocConfig.Builder { - - public abstract PhpDocConfig build(); - - public abstract Builder setApiName(String serviceName); - - public abstract Builder setMethodName(String methodName); - - public abstract Builder setPagedVariant(boolean paged); - - public abstract Builder setReturnType(String returnType); - - public abstract Builder setInitCode(InitCode initCode); - - public abstract Builder setParams(ImmutableList params); - - @Override - protected Builder setInitCodeProxy(InitCode initCode) { - return setInitCode(initCode); - } - - @Override - protected Builder setParamsProxy(ImmutableList params) { - return setParams(params); - } - } -} diff --git a/src/main/java/com/google/api/codegen/php/PhpGapicContext.java b/src/main/java/com/google/api/codegen/php/PhpGapicContext.java deleted file mode 100644 index 0e68505ed0..0000000000 --- a/src/main/java/com/google/api/codegen/php/PhpGapicContext.java +++ /dev/null @@ -1,362 +0,0 @@ -/* Copyright 2016 Google Inc - * - * 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 - * - * http://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.php; - -import com.google.api.codegen.ApiConfig; -import com.google.api.codegen.GapicContext; -import com.google.api.codegen.metacode.FieldSetting; -import com.google.api.codegen.metacode.InitCode; -import com.google.api.codegen.metacode.InitCodeLine; -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.ProtoElement; -import com.google.api.tools.framework.model.ProtoFile; -import com.google.api.tools.framework.model.TypeRef; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type; - -/** - * A GapicContext specialized for PHP. - */ -public class PhpGapicContext extends GapicContext implements PhpContext { - /** - * A map from primitive types in proto to PHP counterparts. - */ - private static final ImmutableMap PRIMITIVE_TYPE_MAP = - ImmutableMap.builder() - .put(Type.TYPE_BOOL, "bool") - .put(Type.TYPE_DOUBLE, "float") - .put(Type.TYPE_FLOAT, "float") - .put(Type.TYPE_INT64, "int") - .put(Type.TYPE_UINT64, "int") - .put(Type.TYPE_SINT64, "int") - .put(Type.TYPE_FIXED64, "int") - .put(Type.TYPE_SFIXED64, "int") - .put(Type.TYPE_INT32, "int") - .put(Type.TYPE_UINT32, "int") - .put(Type.TYPE_SINT32, "int") - .put(Type.TYPE_FIXED32, "int") - .put(Type.TYPE_SFIXED32, "int") - .put(Type.TYPE_STRING, "string") - .put(Type.TYPE_BYTES, "string") - .build(); - - /** - * A map from primitive types in proto to zero value in PHP - */ - private static final ImmutableMap PRIMITIVE_ZERO_VALUE = - ImmutableMap.builder() - .put(Type.TYPE_BOOL, "false") - .put(Type.TYPE_DOUBLE, "0.0") - .put(Type.TYPE_FLOAT, "0.0") - .put(Type.TYPE_INT64, "0") - .put(Type.TYPE_UINT64, "0") - .put(Type.TYPE_SINT64, "0") - .put(Type.TYPE_FIXED64, "0") - .put(Type.TYPE_SFIXED64, "0") - .put(Type.TYPE_INT32, "0") - .put(Type.TYPE_UINT32, "0") - .put(Type.TYPE_SINT32, "0") - .put(Type.TYPE_FIXED32, "0") - .put(Type.TYPE_SFIXED32, "0") - .put(Type.TYPE_STRING, "\"\"") - .put(Type.TYPE_BYTES, "\"\"") - .build(); - - private PhpContextCommon phpCommon; - - public PhpGapicContext(Model model, ApiConfig apiConfig) { - super(model, apiConfig); - } - - @Override - public void resetState(PhpContextCommon phpCommon) { - this.phpCommon = phpCommon; - } - - public PhpContextCommon php() { - return phpCommon; - } - - // Snippet Helpers - // =============== - - /** - * Returns the PHP filename which holds the gRPC service definition. - */ - public String getGrpcFilename(Interface service) { - return service.getFile().getProto().getName().replace(".proto", "_services"); - } - - /** - * Returns the name of the gRPC client class. - */ - public String getGrpcClientName(Interface service) { - String fullyQualifiedClientName = service.getFullName().replaceAll("\\.", "\\\\") + "Client"; - return getTypeName(fullyQualifiedClientName); - } - - public String getTypeName(String typeName) { - int lastBackslashIndex = typeName.lastIndexOf('\\'); - if (lastBackslashIndex < 0) { - throw new IllegalArgumentException("expected fully qualified name"); - } - String shortTypeName = typeName.substring(lastBackslashIndex + 1); - return phpCommon.getMinimallyQualifiedName(typeName, shortTypeName); - } - - /** - * Adds the given type name to the import list. Returns an empty string so that the output is not - * affected in snippets. - */ - public String addImport(String typeName) { - // used for its side effect of adding the type to the import list if the short name - // hasn't been imported yet - getTypeName(typeName); - return ""; - } - - /** - * Returns the PHP representation of a reference to a type. - */ - public String typeName(TypeRef type) { - if (type.isMap()) { - return "array"; - } else if (type.isRepeated()) { - return basicTypeName(type) + "[]"; - } else { - return basicTypeName(type); - } - } - - /** - * Returns the PHP representation of a type, without cardinality. If the type is a primitive, - * basicTypeName returns it in unboxed form. - */ - public String basicTypeName(TypeRef type) { - String result = PRIMITIVE_TYPE_MAP.get(type.getKind()); - if (result != null) { - if (result.contains("\\")) { - // Fully qualified type name, use regular type name resolver. Can skip boxing logic - // because those types are already boxed. - return getTypeName(result); - } - return result; - } - switch (type.getKind()) { - case TYPE_MESSAGE: - return getTypeName(type.getMessageType()); - case TYPE_ENUM: - return getTypeName(type.getEnumType()); - default: - throw new IllegalArgumentException("unknown type kind: " + type.getKind()); - } - } - - /** - * Returns the PHP representation of a zero value for that type, to be used in code sample doc. - * - * Parametric types may use the diamond operator, since the return value will be used only in - * initialization. - */ - public String zeroValue(TypeRef type) { - // Don't call getTypeName; we don't need to import these. - if (type.isMap()) { - return "[]"; - } - if (type.isRepeated()) { - return "[]"; - } - if (PRIMITIVE_ZERO_VALUE.containsKey(type.getKind())) { - return PRIMITIVE_ZERO_VALUE.get(type.getKind()); - } - if (type.isMessage()) { - return "new " + typeName(type) + "()"; - } - return "null"; - } - - public String fullyQualifiedName(TypeRef type) { - return type.getMessageType().getFullName().replaceAll("\\.", "\\\\"); - } - - /** - * Gets the full name of the message or enum type in PHP. - */ - public String getTypeName(ProtoElement elem) { - // Construct the fully-qualified PHP class name - int qualifiedPrefixLength = elem.getFile().getFullName().length() + 1; - String shortName = elem.getFullName().substring(qualifiedPrefixLength); - String name = getPhpPackage(elem.getFile()) + "\\" + shortName; - - return phpCommon.getMinimallyQualifiedName(name, shortName); - } - - public String getServiceName(Interface service) { - return service.getFullName(); - } - - /** - * Gets the PHP package for the given proto file. - */ - public String getPhpPackage(ProtoFile file) { - return file.getProto().getPackage().replaceAll("\\.", "\\\\"); - } - - public Method getFirstMethod(Interface service) { - ImmutableList methods = service.getMethods(); - if (methods.size() > 0) { - return methods.get(0); - } - throw new RuntimeException("No methods available."); - } - - public String returnTypeOrEmpty(TypeRef returnType) { - return messages().isEmptyType(returnType) ? "" : typeName(returnType); - } - - public PhpDocConfig.Builder newPhpDocConfigBuilder() { - return PhpDocConfig.newBuilder(); - } - - /** - * Get a Php formatted primitive value, given a primitive type and a string representation of that - * value. The value must be a valid example of that type. Values of type Bool must be either the - * string 'true' or 'false' (other capitalizations are permitted). - */ - public String renderPrimitiveValue(TypeRef type, String value) { - Type primitiveType = type.getKind(); - if (!PRIMITIVE_TYPE_MAP.containsKey(primitiveType)) { - throw new IllegalArgumentException( - "Initial values are only supported for primitive types, got type " - + type - + ", with value " - + value); - } - switch (primitiveType) { - case TYPE_BOOL: - return value.toLowerCase(); - case TYPE_STRING: - case TYPE_BYTES: - return "\"" + value + "\""; - default: - // Types that do not need to be modified (e.g. TYPE_INT32) are handled here - return value; - } - } - - /** - * Determine whether a given InitCodeLine is a method parameter. This is important for map fields - * because flattened map parameters accept an associative array, while map fields on a request - * object must be a sequential array of MapEntry objects. - */ - public boolean initLineIsParameter(InitCode initCode, InitCodeLine initCodeLine) { - for (FieldSetting fieldSetting : initCode.getArgFields()) { - if (initCodeLine.getIdentifier().equals(fieldSetting.getIdentifier())) { - return true; - } - } - return false; - } - - // Constants - // ========= - - /** - * A set of PHP keywords and built-ins. keywords: http://php.net/manual/en/reserved.keywords.php - */ - private static final ImmutableSet KEYWORD_BUILT_IN_SET = - ImmutableSet.builder() - .add( - "__halt_compiler", - "abstract", - "and", - "array", - "as", - "break", - "callable", - "case", - "catch", - "class", - "clone", - "const", - "continue", - "declare", - "default", - "die", - "do", - "echo", - "else", - "elseif", - "empty", - "enddeclare", - "endfor", - "endforeach", - "endif", - "endswitch", - "endwhile", - "eval", - "exit", - "extends", - "final", - "finally", - "for", - "foreach", - "function", - "global", - "goto", - "if", - "implements", - "include", - "include_once", - "instanceof", - "insteadof", - "interface", - "isset", - "list", - "namespace", - "new", - "or", - "print", - "private", - "protected", - "public", - "require", - "require_once", - "return", - "static", - "switch", - "throw", - "trait", - "try", - "unset", - "use", - "var", - "while", - "xor", - "yield", - "__CLASS__", - "__DIR__", - "__FILE__", - "__FUNCTION__", - "__LINE__", - "__METHOD__", - "__NAMESPACE__", - "__TRAIT__") - .build(); -} diff --git a/src/main/java/com/google/api/codegen/php/PhpSnippetSetRunner.java b/src/main/java/com/google/api/codegen/php/PhpSnippetSetRunner.java index 26fdb4ce1c..75fbf9d088 100644 --- a/src/main/java/com/google/api/codegen/php/PhpSnippetSetRunner.java +++ b/src/main/java/com/google/api/codegen/php/PhpSnippetSetRunner.java @@ -17,6 +17,7 @@ import com.google.api.codegen.CodegenContext; import com.google.api.codegen.GeneratedResult; import com.google.api.codegen.SnippetSetRunner; +import com.google.api.codegen.util.php.PhpTypeTable; import com.google.api.tools.framework.snippet.Doc; import com.google.api.tools.framework.snippet.SnippetSet; import com.google.common.collect.ImmutableMap; @@ -48,15 +49,15 @@ public GeneratedResult generate( ImmutableMap.of("context", context)); String outputFilename = snippets.generateFilename(element).prettyPrint(); - PhpContextCommon phpContextCommon = new PhpContextCommon(); + PhpTypeTable phpTypeTable = new PhpTypeTable(); // TODO don't depend on a cast here PhpContext phpContext = (PhpContext) context; - phpContext.resetState(phpContextCommon); + phpContext.resetState(phpTypeTable); Doc body = snippets.generateBody(element); - List cleanedImports = phpContextCommon.getImports(); + List cleanedImports = phpTypeTable.getImports(); Doc result = snippets.generateClass(element, body, cleanedImports); return GeneratedResult.create(result, outputFilename); diff --git a/src/main/java/com/google/api/codegen/rendering/CommonSnippetSetRunner.java b/src/main/java/com/google/api/codegen/rendering/CommonSnippetSetRunner.java new file mode 100644 index 0000000000..4f62f45fbd --- /dev/null +++ b/src/main/java/com/google/api/codegen/rendering/CommonSnippetSetRunner.java @@ -0,0 +1,48 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.rendering; + +import com.google.api.codegen.viewmodel.ViewModel; +import com.google.api.tools.framework.snippet.Doc; +import com.google.api.tools.framework.snippet.SnippetSet; +import com.google.common.collect.ImmutableMap; + +/** + * CommonSnippetSetRunner takes the view model as input and then uses the + * Snippet Set templating engine to generate an output document. + */ +public class CommonSnippetSetRunner { + + private Object utilObject; + + public CommonSnippetSetRunner(Object utilObject) { + this.utilObject = utilObject; + } + + public Doc generate(ViewModel input) { + SurfaceSnippetSet snippets = + SnippetSet.createSnippetInterface( + SurfaceSnippetSet.class, + input.resourceRoot(), + input.templateFileName(), + ImmutableMap.of("util", utilObject)); + + return snippets.generate(input); + } + + private interface SurfaceSnippetSet { + Doc generate(ViewModel input); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/ApiCallableTransformer.java b/src/main/java/com/google/api/codegen/transformer/ApiCallableTransformer.java new file mode 100644 index 0000000000..32731a6444 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/ApiCallableTransformer.java @@ -0,0 +1,159 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.BundlingConfig; +import com.google.api.codegen.MethodConfig; +import com.google.api.codegen.PageStreamingConfig; +import com.google.api.codegen.viewmodel.ApiCallSettingsView; +import com.google.api.codegen.viewmodel.ApiCallableType; +import com.google.api.codegen.viewmodel.ApiCallableView; +import com.google.api.codegen.viewmodel.BundlingConfigView; +import com.google.api.tools.framework.model.Method; +import com.google.api.tools.framework.model.TypeRef; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ApiCallableTransformer { + + public List generateStaticApiCallables(SurfaceTransformerContext context) { + List callableMembers = new ArrayList<>(); + + for (Method method : context.getInterface().getMethods()) { + callableMembers.addAll(generateStaticApiCallables(context.asMethodContext(method))); + } + + return callableMembers; + } + + public List generateCallSettings(SurfaceTransformerContext context) { + List settingsMembers = new ArrayList<>(); + + for (Method method : context.getInterface().getMethods()) { + settingsMembers.addAll(generateApiCallableSettings(context.asMethodContext(method))); + } + + return settingsMembers; + } + + private List generateStaticApiCallables(MethodTransformerContext context) { + ModelTypeTable typeTable = context.getTypeTable(); + Method method = context.getMethod(); + MethodConfig methodConfig = context.getMethodConfig(); + + List apiCallables = new ArrayList<>(); + + ApiCallableView.Builder apiCallableBuilder = ApiCallableView.newBuilder(); + + apiCallableBuilder.requestTypeName(typeTable.getAndSaveNicknameFor(method.getInputType())); + apiCallableBuilder.responseTypeName(typeTable.getAndSaveNicknameFor(method.getOutputType())); + apiCallableBuilder.name(context.getNamer().getCallableName(method)); + apiCallableBuilder.settingsFunctionName(context.getNamer().getSettingsFunctionName(method)); + + if (methodConfig.isBundling()) { + apiCallableBuilder.type(ApiCallableType.BundlingApiCallable); + } else { + apiCallableBuilder.type(ApiCallableType.SimpleApiCallable); + } + + apiCallables.add(apiCallableBuilder.build()); + + if (methodConfig.isPageStreaming()) { + PageStreamingConfig pageStreaming = methodConfig.getPageStreaming(); + + ApiCallableView.Builder pagedApiCallableBuilder = ApiCallableView.newBuilder(); + + String pagedResponseTypeName = + context + .getNamer() + .getAndSavePagedResponseTypeName( + typeTable, pageStreaming.getResourcesField().getType()); + + pagedApiCallableBuilder.requestTypeName( + typeTable.getAndSaveNicknameFor(method.getInputType())); + pagedApiCallableBuilder.responseTypeName(pagedResponseTypeName); + pagedApiCallableBuilder.name(context.getNamer().getPagedCallableName(method)); + pagedApiCallableBuilder.settingsFunctionName( + context.getNamer().getSettingsFunctionName(method)); + + apiCallables.add(pagedApiCallableBuilder.type(ApiCallableType.PagedApiCallable).build()); + } + + return apiCallables; + } + + private List generateApiCallableSettings(MethodTransformerContext context) { + SurfaceNamer namer = context.getNamer(); + ModelTypeTable typeTable = context.getTypeTable(); + Method method = context.getMethod(); + MethodConfig methodConfig = context.getMethodConfig(); + + ApiCallSettingsView.Builder settings = ApiCallSettingsView.newBuilder(); + + settings.methodName(namer.getApiMethodName(method)); + settings.requestTypeName(typeTable.getAndSaveNicknameFor(method.getInputType())); + settings.responseTypeName(typeTable.getAndSaveNicknameFor(method.getOutputType())); + settings.grpcTypeName( + typeTable.getAndSaveNicknameFor(namer.getGrpcContainerTypeName(context.getInterface()))); + settings.grpcMethodConstant(namer.getGrpcMethodConstant(method)); + settings.retryCodesName(methodConfig.getRetryCodesConfigName()); + settings.retryParamsName(methodConfig.getRetrySettingsConfigName()); + + String notImplementedPrefix = "ApiCallableTransformer.generateApiCallableSettings - "; + settings.resourceTypeName( + namer.getNotImplementedString(notImplementedPrefix + "resourceTypeName")); + settings.pageStreamingDescriptorName( + namer.getNotImplementedString(notImplementedPrefix + "pageStreamingDescriptorName")); + settings.bundlingDescriptorName( + namer.getNotImplementedString(notImplementedPrefix + "bundlingDescriptorName")); + + if (methodConfig.isPageStreaming()) { + namer.addPageStreamingCallSettingsImports(typeTable); + settings.type(ApiCallableType.PagedApiCallable); + TypeRef resourceType = methodConfig.getPageStreaming().getResourcesField().getType(); + settings.resourceTypeName(typeTable.getAndSaveNicknameForElementType(resourceType)); + settings.pageStreamingDescriptorName(namer.getPageStreamingDescriptorConstName(method)); + } else { + if (methodConfig.isBundling()) { + namer.addBundlingCallSettingsImports(typeTable); + settings.type(ApiCallableType.BundlingApiCallable); + settings.bundlingDescriptorName(namer.getBundlingDescriptorConstName(method)); + settings.bundlingConfig(generateBundlingConfig(context)); + } else { + settings.type(ApiCallableType.SimpleApiCallable); + } + } + + settings.memberName(namer.getSettingsMemberName(method)); + settings.fnGetterName(namer.getSettingsMemberName(method)); + + return Arrays.asList(settings.build()); + } + + private BundlingConfigView generateBundlingConfig(MethodTransformerContext context) { + BundlingConfig bundlingConfig = context.getMethodConfig().getBundling(); + BundlingConfigView.Builder bundlingConfigView = BundlingConfigView.newBuilder(); + + bundlingConfigView.elementCountThreshold(bundlingConfig.getElementCountThreshold()); + bundlingConfigView.elementCountLimit(bundlingConfig.getElementCountLimit()); + bundlingConfigView.requestByteThreshold(bundlingConfig.getRequestByteThreshold()); + bundlingConfigView.requestByteLimit(bundlingConfig.getRequestByteLimit()); + bundlingConfigView.delayThresholdMillis(bundlingConfig.getDelayThresholdMillis()); + + return bundlingConfigView.build(); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/ApiMethodTransformer.java b/src/main/java/com/google/api/codegen/transformer/ApiMethodTransformer.java new file mode 100644 index 0000000000..d998d65248 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/ApiMethodTransformer.java @@ -0,0 +1,527 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.CollectionConfig; +import com.google.api.codegen.MethodConfig; +import com.google.api.codegen.PageStreamingConfig; +import com.google.api.codegen.ServiceMessages; +import com.google.api.codegen.util.Name; +import com.google.api.codegen.viewmodel.ApiMethodDocView; +import com.google.api.codegen.viewmodel.ApiMethodType; +import com.google.api.codegen.viewmodel.CallableMethodDetailView; +import com.google.api.codegen.viewmodel.DynamicDefaultableParamView; +import com.google.api.codegen.viewmodel.ListMethodDetailView; +import com.google.api.codegen.viewmodel.MapParamDocView; +import com.google.api.codegen.viewmodel.OptionalArrayMethodView; +import com.google.api.codegen.viewmodel.ParamDocView; +import com.google.api.codegen.viewmodel.PathTemplateCheckView; +import com.google.api.codegen.viewmodel.RequestObjectMethodDetailView; +import com.google.api.codegen.viewmodel.RequestObjectParamView; +import com.google.api.codegen.viewmodel.SimpleParamDocView; +import com.google.api.codegen.viewmodel.StaticApiMethodView; +import com.google.api.codegen.viewmodel.StaticApiMethodView.Builder; +import com.google.api.codegen.viewmodel.UnpagedListCallableMethodDetailView; +import com.google.api.tools.framework.model.Field; +import com.google.api.tools.framework.model.TypeRef; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * ApiMethodTransformer generates view objects from method definitions. + */ +public class ApiMethodTransformer { + private InitCodeTransformer initCodeTransformer; + + public ApiMethodTransformer() { + this.initCodeTransformer = new InitCodeTransformer(); + } + + public StaticApiMethodView generatePagedFlattenedMethod( + MethodTransformerContext context, ImmutableList fields) { + StaticApiMethodView.Builder methodViewBuilder = StaticApiMethodView.newBuilder(); + + setCommonFields(context, methodViewBuilder); + methodViewBuilder.name(context.getNamer().getApiMethodName(context.getMethod())); + setListMethodFields(context, methodViewBuilder); + setFlattenedMethodFields(context, fields, methodViewBuilder); + + return methodViewBuilder.type(ApiMethodType.PagedFlattenedMethod).build(); + } + + public StaticApiMethodView generatePagedRequestObjectMethod(MethodTransformerContext context) { + SurfaceNamer namer = context.getNamer(); + StaticApiMethodView.Builder methodViewBuilder = StaticApiMethodView.newBuilder(); + + setCommonFields(context, methodViewBuilder); + methodViewBuilder.name(namer.getApiMethodName(context.getMethod())); + setListMethodFields(context, methodViewBuilder); + setRequestObjectMethodFields( + context, namer.getPagedCallableMethodName(context.getMethod()), methodViewBuilder); + + return methodViewBuilder.type(ApiMethodType.PagedRequestObjectMethod).build(); + } + + public StaticApiMethodView generatePagedCallableMethod(MethodTransformerContext context) { + SurfaceNamer namer = context.getNamer(); + StaticApiMethodView.Builder methodViewBuilder = StaticApiMethodView.newBuilder(); + + setCommonFields(context, methodViewBuilder); + methodViewBuilder.name(namer.getPagedCallableMethodName(context.getMethod())); + setListMethodFields(context, methodViewBuilder); + setCallableMethodFields( + context, namer.getPagedCallableName(context.getMethod()), methodViewBuilder); + + return methodViewBuilder.type(ApiMethodType.PagedCallableMethod).build(); + } + + public StaticApiMethodView generateUnpagedListCallableMethod(MethodTransformerContext context) { + SurfaceNamer namer = context.getNamer(); + StaticApiMethodView.Builder methodViewBuilder = StaticApiMethodView.newBuilder(); + + setCommonFields(context, methodViewBuilder); + methodViewBuilder.name(namer.getCallableMethodName(context.getMethod())); + setListMethodFields(context, methodViewBuilder); + setCallableMethodFields(context, namer.getCallableName(context.getMethod()), methodViewBuilder); + + String getResourceListCallName = + namer.getGetResourceListCallName( + context.getMethodConfig().getPageStreaming().getResourcesField()); + UnpagedListCallableMethodDetailView unpagedListCallableDetails = + UnpagedListCallableMethodDetailView.newBuilder() + .fnGetResourceListCall(getResourceListCallName) + .build(); + methodViewBuilder.unpagedListCallableMethod(unpagedListCallableDetails); + + methodViewBuilder.responseTypeName( + context.getTypeTable().getAndSaveNicknameFor(context.getMethod().getOutputType())); + + return methodViewBuilder.type(ApiMethodType.UnpagedListCallableMethod).build(); + } + + public StaticApiMethodView generateFlattenedMethod( + MethodTransformerContext context, ImmutableList fields) { + StaticApiMethodView.Builder methodViewBuilder = StaticApiMethodView.newBuilder(); + + setCommonFields(context, methodViewBuilder); + methodViewBuilder.name(context.getNamer().getApiMethodName(context.getMethod())); + setFlattenedMethodFields(context, fields, methodViewBuilder); + setSyncStaticReturnFields(context, methodViewBuilder); + + return methodViewBuilder.type(ApiMethodType.FlattenedMethod).build(); + } + + public StaticApiMethodView generateRequestObjectMethod(MethodTransformerContext context) { + SurfaceNamer namer = context.getNamer(); + StaticApiMethodView.Builder methodViewBuilder = StaticApiMethodView.newBuilder(); + + setCommonFields(context, methodViewBuilder); + methodViewBuilder.name(namer.getApiMethodName(context.getMethod())); + setRequestObjectMethodFields( + context, namer.getCallableMethodName(context.getMethod()), methodViewBuilder); + setSyncStaticReturnFields(context, methodViewBuilder); + + return methodViewBuilder.type(ApiMethodType.RequestObjectMethod).build(); + } + + public StaticApiMethodView generateCallableMethod(MethodTransformerContext context) { + SurfaceNamer namer = context.getNamer(); + StaticApiMethodView.Builder methodViewBuilder = StaticApiMethodView.newBuilder(); + + setCommonFields(context, methodViewBuilder); + methodViewBuilder.name(namer.getCallableMethodName(context.getMethod())); + setCallableMethodFields(context, namer.getCallableName(context.getMethod()), methodViewBuilder); + methodViewBuilder.responseTypeName( + context.getTypeTable().getAndSaveNicknameFor(context.getMethod().getOutputType())); + methodViewBuilder.hasReturnValue( + !ServiceMessages.s_isEmptyType(context.getMethod().getOutputType())); + + return methodViewBuilder.type(ApiMethodType.CallableMethod).build(); + } + + public void setCommonFields( + MethodTransformerContext context, StaticApiMethodView.Builder methodViewBuilder) { + SurfaceNamer namer = context.getNamer(); + methodViewBuilder.apiRequestTypeName( + context.getTypeTable().getAndSaveNicknameFor(context.getMethod().getInputType())); + methodViewBuilder.apiClassName(namer.getApiWrapperClassName(context.getInterface())); + methodViewBuilder.apiVariableName(namer.getApiWrapperVariableName(context.getInterface())); + methodViewBuilder.settingsGetterName(namer.getSettingsFunctionName(context.getMethod())); + } + + private void setListMethodFields( + MethodTransformerContext context, StaticApiMethodView.Builder methodViewBuilder) { + PageStreamingConfig pageStreaming = context.getMethodConfig().getPageStreaming(); + TypeRef resourceType = pageStreaming.getResourcesField().getType(); + String resourceTypeName = context.getTypeTable().getAndSaveNicknameForElementType(resourceType); + methodViewBuilder.listMethod( + ListMethodDetailView.newBuilder().resourceTypeName(resourceTypeName).build()); + methodViewBuilder.responseTypeName( + context.getNamer().getAndSavePagedResponseTypeName(context.getTypeTable(), resourceType)); + methodViewBuilder.hasReturnValue(true); + } + + public void setFlattenedMethodFields( + MethodTransformerContext context, + ImmutableList fields, + StaticApiMethodView.Builder methodViewBuilder) { + SurfaceNamer namer = context.getNamer(); + methodViewBuilder.initCode(initCodeTransformer.generateInitCode(context, fields)); + methodViewBuilder.doc( + ApiMethodDocView.newBuilder() + .mainDocLines(namer.getDocLines(context.getMethod())) + .paramDocs(getMethodParamDocs(context, fields)) + .throwsDocLines(namer.getThrowsDocLines()) + .build()); + + List params = new ArrayList<>(); + for (Field field : fields) { + params.add(generateRequestObjectParam(context, field)); + } + methodViewBuilder.methodParams(params); + methodViewBuilder.requestObjectParams(params); + + methodViewBuilder.pathTemplateChecks(generatePathTemplateChecks(context, fields)); + } + + public void setRequestObjectMethodFields( + MethodTransformerContext context, + String callableMethodName, + StaticApiMethodView.Builder methodViewBuilder) { + SurfaceNamer namer = context.getNamer(); + methodViewBuilder.doc( + ApiMethodDocView.newBuilder() + .mainDocLines(namer.getDocLines(context.getMethod())) + .paramDocs( + Arrays.asList( + getRequestObjectParamDoc(context, context.getMethod().getInputType()))) + .throwsDocLines(namer.getThrowsDocLines()) + .build()); + methodViewBuilder.initCode(initCodeTransformer.generateRequestObjectInitCode(context)); + + methodViewBuilder.methodParams(new ArrayList()); + methodViewBuilder.requestObjectParams(new ArrayList()); + methodViewBuilder.pathTemplateChecks(new ArrayList()); + + RequestObjectMethodDetailView.Builder detailBuilder = + RequestObjectMethodDetailView.newBuilder(); + if (context.getMethodConfig().hasRequestObjectMethod()) { + detailBuilder.accessModifier(context.getNamer().getPublicAccessModifier()); + } else { + detailBuilder.accessModifier(context.getNamer().getPrivateAccessModifier()); + } + detailBuilder.callableMethodName(callableMethodName); + methodViewBuilder.requestObjectMethod(detailBuilder.build()); + } + + private void setCallableMethodFields( + MethodTransformerContext context, String callableName, Builder methodViewBuilder) { + methodViewBuilder.doc( + ApiMethodDocView.newBuilder() + .mainDocLines(context.getNamer().getDocLines(context.getMethod())) + .paramDocs(new ArrayList()) + .throwsDocLines(new ArrayList()) + .build()); + methodViewBuilder.initCode(initCodeTransformer.generateRequestObjectInitCode(context)); + + methodViewBuilder.methodParams(new ArrayList()); + methodViewBuilder.requestObjectParams(new ArrayList()); + methodViewBuilder.pathTemplateChecks(new ArrayList()); + + String genericAwareResponseTypeFullName = + context.getNamer().getGenericAwareResponseTypeName(context.getMethod().getOutputType()); + String genericAwareResponseType = + context.getTypeTable().getAndSaveNicknameFor(genericAwareResponseTypeFullName); + methodViewBuilder.callableMethod( + CallableMethodDetailView.newBuilder() + .genericAwareResponseType(genericAwareResponseType) + .callableName(callableName) + .build()); + } + + public void setSyncStaticReturnFields( + MethodTransformerContext context, StaticApiMethodView.Builder methodViewBuilder) { + String staticReturnTypeFullName = + context.getNamer().getStaticReturnTypeName(context.getMethod(), context.getMethodConfig()); + methodViewBuilder.responseTypeName( + context.getTypeTable().getAndSaveNicknameFor(staticReturnTypeFullName)); + methodViewBuilder.hasReturnValue( + !ServiceMessages.s_isEmptyType(context.getMethod().getOutputType())); + } + + public List generatePathTemplateChecks( + MethodTransformerContext context, ImmutableList fields) { + List pathTemplateChecks = new ArrayList<>(); + for (Field field : fields) { + ImmutableMap fieldNamePatterns = + context.getMethodConfig().getFieldNamePatterns(); + String entityName = fieldNamePatterns.get(field.getSimpleName()); + if (entityName != null) { + CollectionConfig collectionConfig = context.getCollectionConfig(entityName); + PathTemplateCheckView.Builder check = PathTemplateCheckView.newBuilder(); + check.pathTemplateName(context.getNamer().getPathTemplateName(collectionConfig)); + check.paramName(context.getNamer().getVariableName(field)); + + pathTemplateChecks.add(check.build()); + } + } + return pathTemplateChecks; + } + + public OptionalArrayMethodView generateOptionalArrayMethod(MethodTransformerContext context) { + SurfaceNamer namer = context.getNamer(); + OptionalArrayMethodView.Builder apiMethod = OptionalArrayMethodView.newBuilder(); + + if (context.getMethodConfig().isPageStreaming()) { + apiMethod.type(ApiMethodType.PagedOptionalArrayMethod); + } else { + apiMethod.type(ApiMethodType.OptionalArrayMethod); + } + apiMethod.apiClassName(namer.getApiWrapperClassName(context.getInterface())); + apiMethod.apiVariableName(namer.getApiWrapperVariableName(context.getInterface())); + apiMethod.initCode( + initCodeTransformer.generateInitCode( + context, context.getMethodConfig().getRequiredFields())); + + apiMethod.doc(generateOptionalArrayMethodDoc(context)); + + apiMethod.name(namer.getApiMethodName(context.getMethod())); + apiMethod.requestTypeName( + context.getTypeTable().getAndSaveNicknameFor(context.getMethod().getInputType())); + apiMethod.hasReturnValue(!ServiceMessages.s_isEmptyType(context.getMethod().getOutputType())); + apiMethod.key(namer.getMethodKey(context.getMethod())); + apiMethod.grpcMethodName(namer.getGrpcMethodName(context.getMethod())); + + apiMethod.methodParams(generateOptionalArrayMethodParams(context)); + + apiMethod.requiredRequestObjectParams( + generateRequestObjectParams(context, context.getMethodConfig().getRequiredFields())); + apiMethod.optionalRequestObjectParams( + generateRequestObjectParams(context, context.getMethodConfig().getOptionalFields())); + + return apiMethod.build(); + } + + private ApiMethodDocView generateOptionalArrayMethodDoc(MethodTransformerContext context) { + ApiMethodDocView.Builder docBuilder = ApiMethodDocView.newBuilder(); + + docBuilder.mainDocLines(context.getNamer().getDocLines(context.getMethod())); + List paramDocs = + getMethodParamDocs(context, context.getMethodConfig().getRequiredFields()); + paramDocs.add(getOptionalArrayParamDoc(context, context.getMethodConfig().getOptionalFields())); + paramDocs.add(getCallSettingsParamDoc(context)); + docBuilder.paramDocs(paramDocs); + docBuilder.returnTypeName( + context + .getNamer() + .getDynamicReturnTypeName(context.getMethod(), context.getMethodConfig())); + docBuilder.throwsDocLines(new ArrayList()); + + return docBuilder.build(); + } + + private List generateOptionalArrayMethodParams( + MethodTransformerContext context) { + List methodParams = + generateDefaultableParams(context, context.getMethodConfig().getRequiredFields()); + + // TODO create a map TypeRef here instead of an array + // (not done yet because array is sufficient for PHP, and maps are more complex to construct) + TypeRef arrayType = TypeRef.fromPrimitiveName("string").makeRepeated(); + + DynamicDefaultableParamView.Builder optionalArgs = DynamicDefaultableParamView.newBuilder(); + optionalArgs.name(context.getNamer().varName(Name.from("optional", "args"))); + optionalArgs.defaultValue(context.getTypeTable().getZeroValueAndSaveNicknameFor(arrayType)); + methodParams.add(optionalArgs.build()); + + DynamicDefaultableParamView.Builder callSettings = DynamicDefaultableParamView.newBuilder(); + callSettings.name(context.getNamer().varName(Name.from("call", "settings"))); + callSettings.defaultValue(context.getTypeTable().getZeroValueAndSaveNicknameFor(arrayType)); + methodParams.add(callSettings.build()); + + return methodParams; + } + + private List generateDefaultableParams( + MethodTransformerContext context, Iterable fields) { + List methodParams = new ArrayList<>(); + for (Field field : context.getMethodConfig().getRequiredFields()) { + DynamicDefaultableParamView param = + DynamicDefaultableParamView.newBuilder() + .name(context.getNamer().getVariableName(field)) + .defaultValue("") + .build(); + methodParams.add(param); + } + return methodParams; + } + + private List generateRequestObjectParams( + MethodTransformerContext context, Iterable fields) { + List params = new ArrayList<>(); + for (Field field : fields) { + params.add(generateRequestObjectParam(context, field)); + } + return params; + } + + private RequestObjectParamView generateRequestObjectParam( + MethodTransformerContext context, Field field) { + SurfaceNamer namer = context.getNamer(); + RequestObjectParamView.Builder param = RequestObjectParamView.newBuilder(); + param.name(namer.getVariableName(field)); + if (namer.shouldImportRequestObjectParamType(field)) { + param.elementTypeName( + context.getTypeTable().getAndSaveNicknameForElementType(field.getType())); + param.typeName(context.getTypeTable().getAndSaveNicknameFor(field.getType())); + } else { + param.elementTypeName( + namer.getNotImplementedString( + "ApiMethodTransformer.generateRequestObjectParam - elementTypeName")); + param.typeName( + namer.getNotImplementedString( + "ApiMethodTransformer.generateRequestObjectParam - typeName")); + } + param.setCallName(namer.getSetFunctionCallName(field)); + param.isMap(field.getType().isMap()); + param.isArray(!field.getType().isMap() && field.getType().isRepeated()); + return param.build(); + } + + private List getMethodParamDocs( + MethodTransformerContext context, Iterable fields) { + List allDocs = new ArrayList<>(); + for (Field field : fields) { + SimpleParamDocView.Builder paramDoc = SimpleParamDocView.newBuilder(); + paramDoc.paramName(context.getNamer().getVariableName(field)); + paramDoc.typeName(context.getTypeTable().getAndSaveNicknameFor(field.getType())); + + List docLines = null; + MethodConfig methodConfig = context.getMethodConfig(); + if (methodConfig.isPageStreaming() + && methodConfig.getPageStreaming().hasPageSizeField() + && field.equals(methodConfig.getPageStreaming().getPageSizeField())) { + docLines = + Arrays.asList( + new String[] { + "The maximum number of resources contained in the underlying API", + "response. If page streaming is performed per-resource, this", + "parameter does not affect the return value. If page streaming is", + "performed per-page, this determines the maximum number of", + "resources in a page." + }); + } else { + docLines = context.getNamer().getDocLines(field); + } + + paramDoc.firstLine(docLines.get(0)); + paramDoc.remainingLines(docLines.subList(1, docLines.size())); + + allDocs.add(paramDoc.build()); + } + return allDocs; + } + + public SimpleParamDocView getRequestObjectParamDoc( + MethodTransformerContext context, TypeRef typeRef) { + return SimpleParamDocView.newBuilder() + .paramName("request") + .typeName(context.getTypeTable().getAndSaveNicknameFor(typeRef)) + .firstLine("The request object containing all of the parameters for the API call.") + .remainingLines(Arrays.asList()) + .build(); + } + + private ParamDocView getOptionalArrayParamDoc( + MethodTransformerContext context, Iterable fields) { + MapParamDocView.Builder paramDoc = MapParamDocView.newBuilder(); + + Name optionalArgsName = Name.from("optional", "args"); + + paramDoc.paramName(context.getNamer().varName(optionalArgsName)); + paramDoc.typeName(context.getNamer().getOptionalArrayTypeName()); + + List docLines = null; + if (!fields.iterator().hasNext()) { + // TODO figure out a reliable way to line-wrap comments across all languages + // instead of encoding it in the transformer + String retrySettingsDocText = + String.format( + "Optional. There are no optional parameters for this method yet;\n" + + " this %s parameter reserves a spot for future ones.", + context.getNamer().varReference(optionalArgsName)); + docLines = context.getNamer().getDocLines(retrySettingsDocText); + } else { + docLines = Arrays.asList("Optional."); + } + paramDoc.firstLine(docLines.get(0)); + paramDoc.remainingLines(docLines.subList(1, docLines.size())); + + paramDoc.arrayKeyDocs(getMethodParamDocs(context, fields)); + + return paramDoc.build(); + } + + private ParamDocView getCallSettingsParamDoc(MethodTransformerContext context) { + MapParamDocView.Builder paramDoc = MapParamDocView.newBuilder(); + + paramDoc.paramName(context.getNamer().varName(Name.from("call", "settings"))); + paramDoc.typeName(context.getNamer().getOptionalArrayTypeName()); + paramDoc.firstLine("Optional."); + paramDoc.remainingLines(new ArrayList()); + + List arrayKeyDocs = new ArrayList<>(); + SimpleParamDocView.Builder retrySettingsDoc = SimpleParamDocView.newBuilder(); + retrySettingsDoc.typeName(context.getNamer().getRetrySettingsTypeName()); + + Name retrySettingsName = Name.from("retry", "settings"); + Name timeoutMillisName = Name.from("timeout", "millis"); + + retrySettingsDoc.paramName(context.getNamer().varName(retrySettingsName)); + // TODO figure out a reliable way to line-wrap comments across all languages + // instead of encoding it in the transformer + String retrySettingsDocText = + String.format( + "Retry settings to use for this call. If present, then\n%s is ignored.", + context.getNamer().varReference(timeoutMillisName)); + List retrySettingsDocLines = context.getNamer().getDocLines(retrySettingsDocText); + retrySettingsDoc.firstLine(retrySettingsDocLines.get(0)); + retrySettingsDoc.remainingLines(retrySettingsDocLines.subList(1, retrySettingsDocLines.size())); + arrayKeyDocs.add(retrySettingsDoc.build()); + + SimpleParamDocView.Builder timeoutDoc = SimpleParamDocView.newBuilder(); + timeoutDoc.typeName(context.getTypeTable().getAndSaveNicknameFor(TypeRef.of(Type.TYPE_INT32))); + timeoutDoc.paramName(context.getNamer().varName(timeoutMillisName)); + // TODO figure out a reliable way to line-wrap comments across all languages + // instead of encoding it in the transformer + String timeoutMillisDocText = + String.format( + "Timeout to use for this call. Only used if %s\nis not set.", + context.getNamer().varReference(retrySettingsName)); + List timeoutMillisDocLines = context.getNamer().getDocLines(timeoutMillisDocText); + timeoutDoc.firstLine(timeoutMillisDocLines.get(0)); + timeoutDoc.remainingLines(timeoutMillisDocLines.subList(1, timeoutMillisDocLines.size())); + arrayKeyDocs.add(timeoutDoc.build()); + + paramDoc.arrayKeyDocs(arrayKeyDocs); + + return paramDoc.build(); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/BundlingTransformer.java b/src/main/java/com/google/api/codegen/transformer/BundlingTransformer.java new file mode 100644 index 0000000000..15a40f0364 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/BundlingTransformer.java @@ -0,0 +1,105 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.BundlingConfig; +import com.google.api.codegen.MethodConfig; +import com.google.api.codegen.viewmodel.BundlingDescriptorClassView; +import com.google.api.codegen.viewmodel.BundlingPartitionKeyView; +import com.google.api.codegen.viewmodel.FieldCopyView; +import com.google.api.tools.framework.model.FieldSelector; +import com.google.api.tools.framework.model.Method; + +import java.util.ArrayList; +import java.util.List; + +public class BundlingTransformer { + + public List generateDescriptorClasses( + SurfaceTransformerContext context) { + List descriptors = new ArrayList<>(); + + for (Method method : context.getInterface().getMethods()) { + MethodConfig methodConfig = context.getMethodConfig(method); + if (!methodConfig.isBundling()) { + continue; + } + descriptors.add(generateDescriptorClass(context.asMethodContext(method))); + } + + return descriptors; + } + + private BundlingDescriptorClassView generateDescriptorClass(MethodTransformerContext context) { + SurfaceNamer namer = context.getNamer(); + ModelTypeTable typeTable = context.getTypeTable(); + Method method = context.getMethod(); + BundlingConfig bundling = context.getMethodConfig().getBundling(); + + BundlingDescriptorClassView.Builder desc = BundlingDescriptorClassView.newBuilder(); + + desc.name(namer.getBundlingDescriptorConstName(method)); + desc.requestTypeName(typeTable.getAndSaveNicknameFor(method.getInputType())); + desc.responseTypeName(typeTable.getAndSaveNicknameFor(method.getOutputType())); + desc.bundledFieldTypeName( + typeTable.getAndSaveNicknameFor(bundling.getBundledField().getType())); + desc.subresponseTypeName( + typeTable.getAndSaveNicknameFor(bundling.getSubresponseField().getType())); + + desc.partitionKeys(generatePartitionKeys(context)); + desc.discriminatorFieldCopies(generateDiscriminatorFieldCopies(context)); + + desc.fnGetBundledField(namer.getGetFunctionCallName(bundling.getBundledField())); + desc.fnSetBundledField(namer.getSetFunctionCallName(bundling.getBundledField())); + desc.fnGetBundledFieldCount(namer.getGetCountCallName(bundling.getBundledField())); + desc.fnGetSubresponseByIndex(namer.getGetByIndexCallName(bundling.getSubresponseField())); + desc.fnSetSubresponse(namer.getSetFunctionCallName(bundling.getSubresponseField())); + + namer.addBundlingDescriptorImports(typeTable); + + return desc.build(); + } + + private List generatePartitionKeys(MethodTransformerContext context) { + List keys = new ArrayList<>(); + BundlingConfig bundling = context.getMethodConfig().getBundling(); + for (FieldSelector fieldSelector : bundling.getDiscriminatorFields()) { + BundlingPartitionKeyView key = + BundlingPartitionKeyView.newBuilder() + .separatorLiteral("\"|\"") + .fnGetCallName( + context.getNamer().getGetFunctionCallName(fieldSelector.getLastField())) + .build(); + keys.add(key); + } + return keys; + } + + private List generateDiscriminatorFieldCopies(MethodTransformerContext context) { + List fieldCopies = new ArrayList<>(); + BundlingConfig bundling = context.getMethodConfig().getBundling(); + for (FieldSelector fieldSelector : bundling.getDiscriminatorFields()) { + FieldCopyView fieldCopy = + FieldCopyView.newBuilder() + .fnGetFunctionCallName( + context.getNamer().getGetFunctionCallName(fieldSelector.getLastField())) + .fnSetFunctionCallName( + context.getNamer().getSetFunctionCallName(fieldSelector.getLastField())) + .build(); + fieldCopies.add(fieldCopy); + } + return fieldCopies; + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/InitCodeTransformer.java b/src/main/java/com/google/api/codegen/transformer/InitCodeTransformer.java new file mode 100644 index 0000000000..16cdb8ce9a --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/InitCodeTransformer.java @@ -0,0 +1,232 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.CollectionConfig; +import com.google.api.codegen.LanguageUtil; +import com.google.api.codegen.metacode.FieldSetting; +import com.google.api.codegen.metacode.FieldStructureParser; +import com.google.api.codegen.metacode.InitCode; +import com.google.api.codegen.metacode.InitCodeGenerator; +import com.google.api.codegen.metacode.InitCodeLine; +import com.google.api.codegen.metacode.InitValueConfig; +import com.google.api.codegen.metacode.ListInitCodeLine; +import com.google.api.codegen.metacode.MapInitCodeLine; +import com.google.api.codegen.metacode.SimpleInitCodeLine; +import com.google.api.codegen.metacode.StructureInitCodeLine; +import com.google.api.codegen.util.Name; +import com.google.api.codegen.viewmodel.FieldSettingView; +import com.google.api.codegen.viewmodel.FormattedInitValueView; +import com.google.api.codegen.viewmodel.InitCodeLineView; +import com.google.api.codegen.viewmodel.InitCodeView; +import com.google.api.codegen.viewmodel.InitValueView; +import com.google.api.codegen.viewmodel.ListInitCodeLineView; +import com.google.api.codegen.viewmodel.MapEntryView; +import com.google.api.codegen.viewmodel.MapInitCodeLineView; +import com.google.api.codegen.viewmodel.SimpleInitCodeLineView; +import com.google.api.codegen.viewmodel.SimpleInitValueView; +import com.google.api.codegen.viewmodel.StructureInitCodeLineView; +import com.google.api.tools.framework.model.Field; +import com.google.api.tools.framework.model.TypeRef; +import com.google.common.collect.ImmutableMap; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * InitCodeTransformer generates initialization code for a given method and then transforms + * it to a view object which can be rendered by a template engine. + */ +public class InitCodeTransformer { + + public InitCodeView generateInitCode(MethodTransformerContext context, Iterable fields) { + Map initFieldStructure = createInitFieldStructure(context); + InitCodeGenerator generator = new InitCodeGenerator(); + InitCode initCode = + generator.generateRequestFieldInitCode(context.getMethod(), initFieldStructure, fields); + + return InitCodeView.newBuilder() + .lines(generateSurfaceInitCodeLines(context, initCode)) + .fieldSettings(getFieldSettings(context, initCode.getArgFields())) + .build(); + } + + public InitCodeView generateRequestObjectInitCode(MethodTransformerContext context) { + Map initFieldStructure = createInitFieldStructure(context); + InitCodeGenerator generator = new InitCodeGenerator(); + InitCode initCode = + generator.generateRequestObjectInitCode(context.getMethod(), initFieldStructure); + + return InitCodeView.newBuilder() + .lines(generateSurfaceInitCodeLines(context, initCode)) + .fieldSettings(getFieldSettings(context, initCode.getArgFields())) + .build(); + } + + private Map createInitFieldStructure(MethodTransformerContext context) { + Map fieldNamePatterns = context.getMethodConfig().getFieldNamePatterns(); + + ImmutableMap.Builder initValueConfigMap = ImmutableMap.builder(); + for (Map.Entry fieldNamePattern : fieldNamePatterns.entrySet()) { + CollectionConfig collectionConfig = context.getCollectionConfig(fieldNamePattern.getValue()); + String apiWrapperClassName = + context.getNamer().getApiWrapperClassName(context.getInterface()); + InitValueConfig initValueConfig = + InitValueConfig.create(apiWrapperClassName, collectionConfig); + initValueConfigMap.put(fieldNamePattern.getKey(), initValueConfig); + } + Map initFieldStructure = + FieldStructureParser.parseFields( + context.getMethodConfig().getSampleCodeInitFields(), initValueConfigMap.build()); + return initFieldStructure; + } + + private List generateSurfaceInitCodeLines( + MethodTransformerContext context, InitCode initCode) { + List surfaceLines = new ArrayList<>(); + for (InitCodeLine line : initCode.getLines()) { + switch (line.getLineType()) { + case StructureInitLine: + surfaceLines.add(generateStructureInitCodeLine(context, (StructureInitCodeLine) line)); + continue; + case ListInitLine: + surfaceLines.add(generateListInitCodeLine(context, (ListInitCodeLine) line)); + continue; + case SimpleInitLine: + surfaceLines.add(generateSimpleInitCodeLine(context, (SimpleInitCodeLine) line)); + continue; + case MapInitLine: + surfaceLines.add(generateMapInitCodeLine(context, (MapInitCodeLine) line)); + continue; + default: + throw new RuntimeException("unhandled line type: " + line.getLineType()); + } + } + return surfaceLines; + } + + private StructureInitCodeLineView generateStructureInitCodeLine( + MethodTransformerContext context, StructureInitCodeLine line) { + StructureInitCodeLineView.Builder surfaceLine = StructureInitCodeLineView.newBuilder(); + + SurfaceNamer namer = context.getNamer(); + surfaceLine.lineType(line.getLineType()); + surfaceLine.typeName(context.getTypeTable().getAndSaveNicknameFor(line.getType())); + surfaceLine.identifier(namer.getVariableName(line.getIdentifier(), line.getInitValueConfig())); + surfaceLine.fieldSettings(getFieldSettings(context, line.getFieldSettings())); + surfaceLine.initValue(getInitValue(context, line.getType(), line.getInitValueConfig())); + + return surfaceLine.build(); + } + + private ListInitCodeLineView generateListInitCodeLine( + MethodTransformerContext context, ListInitCodeLine line) { + ListInitCodeLineView.Builder surfaceLine = ListInitCodeLineView.newBuilder(); + + SurfaceNamer namer = context.getNamer(); + surfaceLine.lineType(line.getLineType()); + surfaceLine.elementTypeName( + context.getTypeTable().getAndSaveNicknameForElementType(line.getElementType())); + surfaceLine.identifier(namer.getVariableName(line.getIdentifier(), line.getInitValueConfig())); + List elementIdentifiers = new ArrayList<>(); + for (Name identifier : line.getElementIdentifiers()) { + elementIdentifiers.add(namer.varName(identifier)); + } + surfaceLine.elementIdentifiers(elementIdentifiers); + + return surfaceLine.build(); + } + + private SimpleInitCodeLineView generateSimpleInitCodeLine( + MethodTransformerContext context, SimpleInitCodeLine line) { + SimpleInitCodeLineView.Builder surfaceLine = SimpleInitCodeLineView.newBuilder(); + + SurfaceNamer namer = context.getNamer(); + surfaceLine.lineType(line.getLineType()); + surfaceLine.typeName(context.getTypeTable().getAndSaveNicknameFor(line.getType())); + surfaceLine.identifier(namer.getVariableName(line.getIdentifier(), line.getInitValueConfig())); + surfaceLine.initValue(getInitValue(context, line.getType(), line.getInitValueConfig())); + + return surfaceLine.build(); + } + + private InitCodeLineView generateMapInitCodeLine( + MethodTransformerContext context, MapInitCodeLine line) { + MapInitCodeLineView.Builder surfaceLine = MapInitCodeLineView.newBuilder(); + + ModelTypeTable typeTable = context.getTypeTable(); + surfaceLine.lineType(line.getLineType()); + surfaceLine.keyTypeName(typeTable.getAndSaveNicknameFor(line.getKeyType())); + surfaceLine.valueTypeName(typeTable.getAndSaveNicknameFor(line.getValueType())); + surfaceLine.identifier( + context.getNamer().getVariableName(line.getIdentifier(), line.getInitValueConfig())); + List entries = new ArrayList<>(); + for (Map.Entry entry : line.getElementIdentifierMap().entrySet()) { + MapEntryView.Builder mapEntry = MapEntryView.newBuilder(); + mapEntry.key(typeTable.renderPrimitiveValue(line.getKeyType(), entry.getKey())); + mapEntry.value( + context.getNamer().getVariableName(line.getElementIdentifierValue(entry.getKey()), null)); + entries.add(mapEntry.build()); + } + surfaceLine.initEntries(entries); + + return surfaceLine.build(); + } + + private InitValueView getInitValue( + MethodTransformerContext context, TypeRef type, InitValueConfig initValueConfig) { + if (initValueConfig.hasFormattingConfig()) { + FormattedInitValueView.Builder initValue = FormattedInitValueView.newBuilder(); + + initValue.apiWrapperName(context.getNamer().getApiWrapperClassName(context.getInterface())); + initValue.formatFunctionName( + context.getNamer().getFormatFunctionName(initValueConfig.getCollectionConfig())); + List formatFunctionArgs = new ArrayList<>(); + for (String var : initValueConfig.getCollectionConfig().getNameTemplate().vars()) { + formatFunctionArgs.add("\"[" + LanguageUtil.lowerUnderscoreToUpperUnderscore(var) + "]\""); + } + initValue.formatArgs(formatFunctionArgs); + + return initValue.build(); + } else { + SimpleInitValueView.Builder initValue = SimpleInitValueView.newBuilder(); + + if (initValueConfig.hasInitialValue()) { + initValue.initialValue( + context.getTypeTable().renderPrimitiveValue(type, initValueConfig.getInitialValue())); + } else { + initValue.initialValue(context.getTypeTable().getZeroValueAndSaveNicknameFor(type)); + } + + return initValue.build(); + } + } + + private List getFieldSettings( + MethodTransformerContext context, Iterable fieldSettings) { + SurfaceNamer namer = context.getNamer(); + List allSettings = new ArrayList<>(); + for (FieldSetting setting : fieldSettings) { + FieldSettingView.Builder fieldSetting = FieldSettingView.newBuilder(); + fieldSetting.fnSetFunctionCallName( + namer.getSetFunctionCallName(setting.getType(), setting.getFieldName())); + fieldSetting.identifier( + namer.getVariableName(setting.getIdentifier(), setting.getInitValueConfig())); + allSettings.add(fieldSetting.build()); + } + return allSettings; + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/MethodTransformerContext.java b/src/main/java/com/google/api/codegen/transformer/MethodTransformerContext.java new file mode 100644 index 0000000000..4fc9177170 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/MethodTransformerContext.java @@ -0,0 +1,66 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.ApiConfig; +import com.google.api.codegen.CollectionConfig; +import com.google.api.codegen.InterfaceConfig; +import com.google.api.codegen.MethodConfig; +import com.google.api.tools.framework.model.Interface; +import com.google.api.tools.framework.model.Method; +import com.google.auto.value.AutoValue; + +import java.util.Collection; + +/** + * The context for transforming a method to a view model object. + */ +@AutoValue +public abstract class MethodTransformerContext { + public static MethodTransformerContext create( + Interface interfaze, + ApiConfig apiConfig, + ModelTypeTable typeTable, + SurfaceNamer namer, + Method method, + MethodConfig methodConfig) { + return new AutoValue_MethodTransformerContext( + interfaze, apiConfig, typeTable, namer, method, methodConfig); + } + + public abstract Interface getInterface(); + + public abstract ApiConfig getApiConfig(); + + public abstract ModelTypeTable getTypeTable(); + + public abstract SurfaceNamer getNamer(); + + public abstract Method getMethod(); + + public abstract MethodConfig getMethodConfig(); + + public InterfaceConfig getInterfaceConfig() { + return getApiConfig().getInterfaceConfig(getInterface()); + } + + public Collection getCollectionConfigs() { + return getInterfaceConfig().getCollectionConfigs(); + } + + public CollectionConfig getCollectionConfig(String entityName) { + return getInterfaceConfig().getCollectionConfig(entityName); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/ModelToViewTransformer.java b/src/main/java/com/google/api/codegen/transformer/ModelToViewTransformer.java new file mode 100644 index 0000000000..421309da3f --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/ModelToViewTransformer.java @@ -0,0 +1,31 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.ApiConfig; +import com.google.api.codegen.viewmodel.ViewModel; +import com.google.api.tools.framework.model.Model; + +import java.util.List; + +/** + * A ModelToViewTransformer transforms a Model into a list of + * ViewModel instances that can be rendered by a template engine. + */ +public interface ModelToViewTransformer { + List transform(Model model, ApiConfig apiConfig); + + List getTemplateFileNames(); +} diff --git a/src/main/java/com/google/api/codegen/transformer/ModelTypeFormatter.java b/src/main/java/com/google/api/codegen/transformer/ModelTypeFormatter.java new file mode 100644 index 0000000000..a73fc09af5 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/ModelTypeFormatter.java @@ -0,0 +1,52 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.tools.framework.model.ProtoElement; +import com.google.api.tools.framework.model.TypeRef; + +/** + * A read-only interface for mapping TypeRef instances to a corresponding + * String representation for a particular language. + * + * Passing this type ensures that mutable functionality in derived classes + * won't be called. + */ +public interface ModelTypeFormatter { + /** + * Get the full name for the given type. + */ + String getFullNameFor(TypeRef type); + + /** + * Get the full name for the given proto element. + */ + String getFullNameFor(ProtoElement element); + + /** + * Get the full name for the element type of the given type. + */ + String getFullNameForElementType(TypeRef type); + + /** + * Returns the nickname for the given type (without adding the full name to the import set). + */ + String getNicknameFor(TypeRef type); + + /** + * Renders the primitive value of the given type. + */ + String renderPrimitiveValue(TypeRef type, String key); +} diff --git a/src/main/java/com/google/api/codegen/transformer/ModelTypeFormatterImpl.java b/src/main/java/com/google/api/codegen/transformer/ModelTypeFormatterImpl.java new file mode 100644 index 0000000000..0a82f76025 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/ModelTypeFormatterImpl.java @@ -0,0 +1,57 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.tools.framework.model.ProtoElement; +import com.google.api.tools.framework.model.TypeRef; + +/** + * Default implementation of ModelTypeFormatter. + */ +public class ModelTypeFormatterImpl implements ModelTypeFormatter { + private ModelTypeNameConverter typeNameConverter; + + /** + * Standard constructor. + */ + public ModelTypeFormatterImpl(ModelTypeNameConverter typeNameConverter) { + this.typeNameConverter = typeNameConverter; + } + + @Override + public String getFullNameFor(TypeRef type) { + return typeNameConverter.getTypeName(type).getFullName(); + } + + @Override + public String getFullNameFor(ProtoElement element) { + return typeNameConverter.getTypeName(element).getFullName(); + } + + @Override + public String getFullNameForElementType(TypeRef type) { + return typeNameConverter.getTypeNameForElementType(type).getFullName(); + } + + @Override + public String getNicknameFor(TypeRef type) { + return typeNameConverter.getTypeName(type).getNickname(); + } + + @Override + public String renderPrimitiveValue(TypeRef type, String value) { + return typeNameConverter.renderPrimitiveValue(type, value); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/ModelTypeNameConverter.java b/src/main/java/com/google/api/codegen/transformer/ModelTypeNameConverter.java new file mode 100644 index 0000000000..93a60cdcf4 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/ModelTypeNameConverter.java @@ -0,0 +1,51 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.util.TypeName; +import com.google.api.codegen.util.TypedValue; +import com.google.api.tools.framework.model.ProtoElement; +import com.google.api.tools.framework.model.TypeRef; + +/** + * ModelTypeNameConverter maps TypeRef instances to TypeName instances. + */ +public interface ModelTypeNameConverter { + /** + * Provides a TypeName for the given TypeRef. + */ + TypeName getTypeName(TypeRef type); + + /** + * Provides a TypeName for the element type of the given TypeRef. + */ + TypeName getTypeNameForElementType(TypeRef type); + + /** + * Provides a TypeName for the given ProtoElement. + */ + TypeName getTypeName(ProtoElement elem); + + /** + * Provides a TypedValue containing the zero value of the given + * type, plus the TypeName of the type. + */ + TypedValue getZeroValue(TypeRef type); + + /** + * Renders the given value if it is a primitive type. + */ + String renderPrimitiveValue(TypeRef type, String value); +} diff --git a/src/main/java/com/google/api/codegen/transformer/ModelTypeTable.java b/src/main/java/com/google/api/codegen/transformer/ModelTypeTable.java new file mode 100644 index 0000000000..545a3e4e43 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/ModelTypeTable.java @@ -0,0 +1,126 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.util.TypeName; +import com.google.api.codegen.util.TypeTable; +import com.google.api.tools.framework.model.ProtoElement; +import com.google.api.tools.framework.model.TypeRef; + +import java.util.List; + +/** + * A ModelTypeTable manages the imports for a set of fully-qualified type names, and + * provides helper methods for importing instances of TypeRef. + */ +public class ModelTypeTable implements ModelTypeFormatter { + private ModelTypeFormatterImpl typeFormatter; + private TypeTable typeTable; + private ModelTypeNameConverter typeNameConverter; + + /** + * Standard constructor. + */ + public ModelTypeTable(TypeTable typeTable, ModelTypeNameConverter typeNameConverter) { + this.typeFormatter = new ModelTypeFormatterImpl(typeNameConverter); + this.typeTable = typeTable; + this.typeNameConverter = typeNameConverter; + } + + @Override + public String getFullNameFor(TypeRef type) { + return typeFormatter.getFullNameFor(type); + } + + @Override + public String getFullNameFor(ProtoElement element) { + return typeFormatter.getFullNameFor(element); + } + + @Override + public String getFullNameForElementType(TypeRef type) { + return typeFormatter.getFullNameForElementType(type); + } + + @Override + public String getNicknameFor(TypeRef type) { + return typeFormatter.getNicknameFor(type); + } + + @Override + public String renderPrimitiveValue(TypeRef type, String value) { + return typeFormatter.renderPrimitiveValue(type, value); + } + + /** + * Creates a new ModelTypeTable of the same concrete type, but with an empty import set. + */ + public ModelTypeTable cloneEmpty() { + return new ModelTypeTable(typeTable.cloneEmpty(), typeNameConverter); + } + + /** + * Compute the nickname for the given fullName and save it in the import set. + */ + public void saveNicknameFor(String fullName) { + getAndSaveNicknameFor(fullName); + } + + /** + * Computes the nickname for the given full name, adds the full name to the import set, + * and returns the nickname. + */ + public String getAndSaveNicknameFor(String fullName) { + return typeTable.getAndSaveNicknameFor(fullName); + } + + /** + * Computes the nickname for the given type, adds the full name to the import set, + * and returns the nickname. + */ + public String getAndSaveNicknameFor(TypeRef type) { + return typeTable.getAndSaveNicknameFor(typeNameConverter.getTypeName(type)); + } + + /** + * This function will compute the nickname for the element type, add the full name to the + * import set, and then return the nickname. If the given type is repeated, then the + * element type is the contained type; if the type is not a repeated type, then the element + * type is the boxed form of the type. + */ + public String getAndSaveNicknameForElementType(TypeRef type) { + return typeTable.getAndSaveNicknameFor(typeNameConverter.getTypeNameForElementType(type)); + } + + public String getAndSaveNicknameForContainer(String containerFullName, String elementFullName) { + TypeName completeTypeName = typeTable.getContainerTypeName(containerFullName, elementFullName); + return typeTable.getAndSaveNicknameFor(completeTypeName); + } + + /** + * If the given type is not implicitly imported, the add it to the import set, then return + * the zero value for that type. + */ + public String getZeroValueAndSaveNicknameFor(TypeRef type) { + return typeNameConverter.getZeroValue(type).getValueAndSaveTypeNicknameIn(typeTable); + } + + /** + * Returns the imports accumulated so far. + */ + public List getImports() { + return typeTable.getImports(); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/PageStreamingTransformer.java b/src/main/java/com/google/api/codegen/transformer/PageStreamingTransformer.java new file mode 100644 index 0000000000..a3a6c1033b --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/PageStreamingTransformer.java @@ -0,0 +1,100 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.MethodConfig; +import com.google.api.codegen.PageStreamingConfig; +import com.google.api.codegen.util.Name; +import com.google.api.codegen.viewmodel.PageStreamingDescriptorClassView; +import com.google.api.codegen.viewmodel.PageStreamingDescriptorView; +import com.google.api.tools.framework.model.Method; +import com.google.api.tools.framework.model.TypeRef; + +import java.util.ArrayList; +import java.util.List; + +/** + * PageStreamingTransformer generates view objects for page streaming from a service model. + */ +public class PageStreamingTransformer { + + public List generateDescriptors(SurfaceTransformerContext context) { + List descriptors = new ArrayList<>(); + + for (Method method : context.getInterface().getMethods()) { + MethodConfig methodConfig = context.getMethodConfig(method); + if (!methodConfig.isPageStreaming()) { + continue; + } + context.getNamer().addPageStreamingDescriptorImports(context.getTypeTable()); + PageStreamingConfig pageStreaming = methodConfig.getPageStreaming(); + + PageStreamingDescriptorView.Builder descriptor = PageStreamingDescriptorView.newBuilder(); + descriptor.varName(context.getNamer().getPageStreamingDescriptorName(method)); + descriptor.requestTokenFieldName(pageStreaming.getRequestTokenField().getSimpleName()); + descriptor.responseTokenFieldName(pageStreaming.getResponseTokenField().getSimpleName()); + descriptor.resourcesFieldName(pageStreaming.getResourcesField().getSimpleName()); + descriptor.methodName(Name.upperCamel(method.getSimpleName()).toLowerCamel()); + + descriptors.add(descriptor.build()); + } + + return descriptors; + } + + public List generateDescriptorClasses( + SurfaceTransformerContext context) { + List descriptors = new ArrayList<>(); + + context.getNamer().addPageStreamingDescriptorImports(context.getTypeTable()); + for (Method method : context.getInterface().getMethods()) { + MethodConfig methodConfig = context.getMethodConfig(method); + if (!methodConfig.isPageStreaming()) { + continue; + } + descriptors.add(generateDescriptorClass(context.asMethodContext(method))); + } + + return descriptors; + } + + private PageStreamingDescriptorClassView generateDescriptorClass( + MethodTransformerContext context) { + SurfaceNamer namer = context.getNamer(); + ModelTypeTable typeTable = context.getTypeTable(); + Method method = context.getMethod(); + PageStreamingConfig pageStreaming = context.getMethodConfig().getPageStreaming(); + + PageStreamingDescriptorClassView.Builder desc = PageStreamingDescriptorClassView.newBuilder(); + + desc.name(namer.getPageStreamingDescriptorConstName(method)); + desc.requestTypeName(typeTable.getAndSaveNicknameFor(method.getInputType())); + desc.responseTypeName(typeTable.getAndSaveNicknameFor(method.getOutputType())); + + TypeRef resourceType = pageStreaming.getResourcesField().getType(); + desc.resourceTypeName(context.getTypeTable().getAndSaveNicknameForElementType(resourceType)); + + TypeRef tokenType = pageStreaming.getResponseTokenField().getType(); + desc.tokenTypeName(typeTable.getAndSaveNicknameFor(tokenType)); + + desc.defaultTokenValue(context.getTypeTable().getZeroValueAndSaveNicknameFor(tokenType)); + + desc.fnSetRequestToken(namer.getSetFunctionCallName(pageStreaming.getRequestTokenField())); + desc.fnGetResponseToken(namer.getGetFunctionCallName(pageStreaming.getResponseTokenField())); + desc.fnGetResourcesField(namer.getGetFunctionCallName(pageStreaming.getResourcesField())); + + return desc.build(); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/PathTemplateTransformer.java b/src/main/java/com/google/api/codegen/transformer/PathTemplateTransformer.java new file mode 100644 index 0000000000..c078a976d8 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/PathTemplateTransformer.java @@ -0,0 +1,107 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.CollectionConfig; +import com.google.api.codegen.viewmodel.FormatResourceFunctionView; +import com.google.api.codegen.viewmodel.ParseResourceFunctionView; +import com.google.api.codegen.viewmodel.PathTemplateView; +import com.google.api.codegen.viewmodel.PathTemplateGetterFunctionView; +import com.google.api.codegen.viewmodel.ResourceIdParamView; + +import java.util.ArrayList; +import java.util.List; + +/** + * PathTemplateTransformer generates view objects for path templates from a service model. + */ +public class PathTemplateTransformer { + + public List generatePathTemplates(SurfaceTransformerContext context) { + List pathTemplates = new ArrayList<>(); + + for (CollectionConfig collectionConfig : context.getCollectionConfigs()) { + PathTemplateView.Builder pathTemplate = PathTemplateView.newBuilder(); + pathTemplate.name(context.getNamer().getPathTemplateName(collectionConfig)); + pathTemplate.pattern(collectionConfig.getNamePattern()); + pathTemplates.add(pathTemplate.build()); + } + + return pathTemplates; + } + + public List generateFormatResourceFunctions( + SurfaceTransformerContext context) { + List functions = new ArrayList<>(); + + SurfaceNamer namer = context.getNamer(); + for (CollectionConfig collectionConfig : context.getCollectionConfigs()) { + FormatResourceFunctionView.Builder function = FormatResourceFunctionView.newBuilder(); + function.entityName(collectionConfig.getEntityName()); + function.name(namer.getFormatFunctionName(collectionConfig)); + function.pathTemplateName(namer.getPathTemplateName(collectionConfig)); + function.pathTemplateGetterName(namer.getPathTemplateNameGetter(collectionConfig)); + List resourceIdParams = new ArrayList<>(); + for (String var : collectionConfig.getNameTemplate().vars()) { + ResourceIdParamView param = + ResourceIdParamView.newBuilder().name(namer.getParamName(var)).templateKey(var).build(); + resourceIdParams.add(param); + } + function.resourceIdParams(resourceIdParams); + + functions.add(function.build()); + } + + return functions; + } + + public List generateParseResourceFunctions( + SurfaceTransformerContext context) { + List functions = new ArrayList<>(); + + SurfaceNamer namer = context.getNamer(); + for (CollectionConfig collectionConfig : context.getCollectionConfigs()) { + for (String var : collectionConfig.getNameTemplate().vars()) { + ParseResourceFunctionView.Builder function = ParseResourceFunctionView.newBuilder(); + function.entityName(namer.getEntityName(collectionConfig)); + function.name(namer.getParseFunctionName(var, collectionConfig)); + function.pathTemplateName(namer.getPathTemplateName(collectionConfig)); + function.pathTemplateGetterName(namer.getPathTemplateNameGetter(collectionConfig)); + function.entityNameParamName(namer.getEntityNameParamName(collectionConfig)); + function.outputResourceId(var); + + functions.add(function.build()); + } + } + + return functions; + } + + public List generatePathTemplateGetterFunctions( + SurfaceTransformerContext context) { + List functions = new ArrayList<>(); + + SurfaceNamer namer = context.getNamer(); + for (CollectionConfig collectionConfig : context.getCollectionConfigs()) { + PathTemplateGetterFunctionView.Builder function = PathTemplateGetterFunctionView.newBuilder(); + function.name(namer.getPathTemplateNameGetter(collectionConfig)); + function.pathTemplateName(namer.getPathTemplateName(collectionConfig)); + function.pattern(collectionConfig.getNamePattern()); + functions.add(function.build()); + } + + return functions; + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/ServiceTransformer.java b/src/main/java/com/google/api/codegen/transformer/ServiceTransformer.java new file mode 100644 index 0000000000..a4ea7ba702 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/ServiceTransformer.java @@ -0,0 +1,38 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.viewmodel.ApiMethodView; +import com.google.api.codegen.viewmodel.ServiceDocView; + +import java.util.List; + +public class ServiceTransformer { + + public ServiceDocView generateServiceDoc( + SurfaceTransformerContext context, ApiMethodView exampleApiMethod) { + SurfaceNamer namer = context.getNamer(); + ServiceDocView.Builder serviceDoc = ServiceDocView.newBuilder(); + List docLines = context.getNamer().getDocLines(context.getInterface()); + serviceDoc.firstLine(docLines.get(0)); + serviceDoc.remainingLines(docLines.subList(1, docLines.size())); + serviceDoc.exampleApiMethod(exampleApiMethod); + serviceDoc.apiVarName(namer.getApiWrapperVariableName(context.getInterface())); + serviceDoc.apiClassName(namer.getApiWrapperClassName(context.getInterface())); + serviceDoc.settingsVarName(namer.getApiSettingsVariableName(context.getInterface())); + serviceDoc.settingsClassName(namer.getApiSettingsClassName(context.getInterface())); + return serviceDoc.build(); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/SurfaceNamer.java b/src/main/java/com/google/api/codegen/transformer/SurfaceNamer.java new file mode 100644 index 0000000000..af8519753b --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/SurfaceNamer.java @@ -0,0 +1,310 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.CollectionConfig; +import com.google.api.codegen.MethodConfig; +import com.google.api.codegen.metacode.InitValueConfig; +import com.google.api.codegen.util.CommonRenderingUtil; +import com.google.api.codegen.util.Name; +import com.google.api.codegen.util.NameFormatter; +import com.google.api.codegen.util.NameFormatterDelegator; +import com.google.api.codegen.util.NamePath; +import com.google.api.codegen.util.TypeNameConverter; +import com.google.api.tools.framework.aspects.documentation.model.DocumentationUtil; +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.ProtoElement; +import com.google.api.tools.framework.model.TypeRef; + +import java.util.ArrayList; +import java.util.List; + +/** + * A SurfaceNamer provides language-specific names for specific components of a view for a surface. + * + * Naming is composed of two steps: + * + * 1. Composing a Name instance with the name pieces + * 2. Formatting the Name for the particular type of identifier needed. + * + * This class delegates step 2 to the provided name formatter, which generally + * would be a language-specific namer. + */ +public class SurfaceNamer extends NameFormatterDelegator { + private ModelTypeFormatter modelTypeFormatter; + private TypeNameConverter typeNameConverter; + + public SurfaceNamer( + NameFormatter languageNamer, + ModelTypeFormatter modelTypeFormatter, + TypeNameConverter typeNameConverter) { + super(languageNamer); + this.modelTypeFormatter = modelTypeFormatter; + this.typeNameConverter = typeNameConverter; + } + + public ModelTypeFormatter getModelTypeFormatter() { + return modelTypeFormatter; + } + + public String getNotImplementedString(String feature) { + return "$ NOT IMPLEMENTED: " + feature + " $"; + } + + public String getApiWrapperClassName(Interface interfaze) { + return className(Name.upperCamel(interfaze.getSimpleName(), "Api")); + } + + public String getApiWrapperVariableName(Interface interfaze) { + return varName(Name.upperCamel(interfaze.getSimpleName(), "Api")); + } + + public String getApiSettingsClassName(Interface interfaze) { + return className(Name.upperCamel(interfaze.getSimpleName(), "Settings")); + } + + public String getApiSettingsVariableName(Interface interfaze) { + return varName(Name.upperCamel(interfaze.getSimpleName(), "Settings")); + } + + public String getApiSettingsBuilderVarName(Interface interfaze) { + return varName(Name.upperCamel(interfaze.getSimpleName(), "SettingsBuilder")); + } + + public String getVariableName(Name identifier, InitValueConfig initValueConfig) { + if (initValueConfig == null || !initValueConfig.hasFormattingConfig()) { + return varName(identifier); + } else { + return varName(Name.from("formatted").join(identifier)); + } + } + + public String getSetFunctionCallName(Field field) { + return getSetFunctionCallName(field.getType(), Name.from(field.getSimpleName())); + } + + public String getSetFunctionCallName(TypeRef type, Name identifier) { + if (type.isMap()) { + return methodName(Name.from("put", "all").join(identifier)); + } else if (type.isRepeated()) { + return methodName(Name.from("add", "all").join(identifier)); + } else { + return methodName(Name.from("set").join(identifier)); + } + } + + public String getGetFunctionCallName(Field field) { + return getGetFunctionCallName(field.getType(), Name.from(field.getSimpleName())); + } + + public String getGetFunctionCallName(TypeRef type, Name identifier) { + if (type.isRepeated()) { + return methodName(Name.from("get").join(identifier).join("list")); + } else { + return methodName(Name.from("get").join(identifier)); + } + } + + public String getGetCountCallName(Field field) { + if (field.isRepeated()) { + return methodName(Name.from("get", field.getSimpleName(), "count")); + } else { + throw new IllegalArgumentException( + "Non-repeated field " + field.getSimpleName() + " has no count function."); + } + } + + public String getGetByIndexCallName(Field field) { + if (field.isRepeated()) { + return methodName(Name.from("get", field.getSimpleName())); + } else { + throw new IllegalArgumentException( + "Non-repeated field " + field.getSimpleName() + " has no get-by-index function."); + } + } + + public String getPathTemplateName(CollectionConfig collectionConfig) { + return inittedConstantName(Name.from(collectionConfig.getEntityName(), "path", "template")); + } + + public String getPathTemplateNameGetter(CollectionConfig collectionConfig) { + return methodName(Name.from("get", collectionConfig.getEntityName(), "name", "template")); + } + + public String getFormatFunctionName(CollectionConfig collectionConfig) { + return staticFunctionName(Name.from("format", collectionConfig.getEntityName(), "name")); + } + + public String getParseFunctionName(String var, CollectionConfig collectionConfig) { + return staticFunctionName( + Name.from("parse", var, "from", collectionConfig.getEntityName(), "name")); + } + + public String getEntityName(CollectionConfig collectionConfig) { + return varName(Name.from(collectionConfig.getEntityName())); + } + + public String getEntityNameParamName(CollectionConfig collectionConfig) { + return varName(Name.from(collectionConfig.getEntityName(), "name")); + } + + public String getParamName(String var) { + return varName(Name.from(var)); + } + + public String getPageStreamingDescriptorName(Method method) { + return varName(Name.upperCamel(method.getSimpleName(), "PageStreamingDescriptor")); + } + + public String getPageStreamingDescriptorConstName(Method method) { + return inittedConstantName(Name.upperCamel(method.getSimpleName()).join("page_str_desc")); + } + + public String getBundlingDescriptorConstName(Method method) { + return inittedConstantName(Name.upperCamel(method.getSimpleName()).join("bundling_desc")); + } + + public void addPageStreamingDescriptorImports(ModelTypeTable typeTable) { + // do nothing + } + + public void addBundlingDescriptorImports(ModelTypeTable typeTable) { + // do nothing + } + + public void addPageStreamingCallSettingsImports(ModelTypeTable typeTable) { + // do nothing + } + + public void addBundlingCallSettingsImports(ModelTypeTable typeTable) { + // do nothing + } + + public String getMethodKey(Method method) { + return keyName(Name.upperCamel(method.getSimpleName())); + } + + public String getClientConfigPath(Interface service) { + return getNotImplementedString("SurfaceNamer.getClientConfigPath"); + } + + public String getGrpcClientTypeName(Interface service) { + NamePath namePath = typeNameConverter.getNamePath(modelTypeFormatter.getFullNameFor(service)); + String className = className(Name.upperCamel(namePath.getHead(), "Client")); + return qualifiedName(namePath.withHead(className)); + } + + public String getGrpcContainerTypeName(Interface service) { + NamePath namePath = typeNameConverter.getNamePath(modelTypeFormatter.getFullNameFor(service)); + String className = className(Name.upperCamel(namePath.getHead(), "Grpc")); + return qualifiedName(namePath.withHead(className)); + } + + public String getGrpcMethodConstant(Method method) { + return inittedConstantName(Name.from("method").join(Name.upperCamel(method.getSimpleName()))); + } + + public String getApiMethodName(Method method) { + return methodName(Name.upperCamel(method.getSimpleName())); + } + + public String getVariableName(Field field) { + return varName(Name.from(field.getSimpleName())); + } + + public boolean shouldImportRequestObjectParamType(Field field) { + return true; + } + + public List getDocLines(String text) { + return CommonRenderingUtil.getDocLines(text); + } + + public List getDocLines(ProtoElement element) { + return getDocLines(DocumentationUtil.getDescription(element)); + } + + public List getThrowsDocLines() { + return new ArrayList<>(); + } + + public String getPublicAccessModifier() { + return "public"; + } + + public String getPrivateAccessModifier() { + return "private"; + } + + public String getGrpcMethodName(Method method) { + // This might seem silly, but it makes clear what we're dealing with (upper camel). + // This is language-independent because of gRPC conventions. + return Name.upperCamel(method.getSimpleName()).toUpperCamel(); + } + + public String getRetrySettingsTypeName() { + return getNotImplementedString("SurfaceNamer.getRetrySettingsClassName"); + } + + public String getOptionalArrayTypeName() { + return getNotImplementedString("SurfaceNamer.getOptionalArrayTypeName"); + } + + public String getDynamicReturnTypeName(Method method, MethodConfig methodConfig) { + return getNotImplementedString("SurfaceNamer.getDynamicReturnTypeName"); + } + + public String getStaticReturnTypeName(Method method, MethodConfig methodConfig) { + return getNotImplementedString("SurfaceNamer.getStaticReturnTypeName"); + } + + public String getPagedCallableMethodName(Method method) { + return methodName(Name.upperCamel(method.getSimpleName(), "PagedCallable")); + } + + public String getPagedCallableName(Method method) { + return varName(Name.upperCamel(method.getSimpleName(), "PagedCallable")); + } + + public String getCallableMethodName(Method method) { + return methodName(Name.upperCamel(method.getSimpleName(), "Callable")); + } + + public String getCallableName(Method method) { + return varName(Name.upperCamel(method.getSimpleName(), "Callable")); + } + + public String getSettingsMemberName(Method method) { + return methodName(Name.upperCamel(method.getSimpleName(), "Settings")); + } + + public String getSettingsFunctionName(Method method) { + return getSettingsMemberName(method); + } + + public String getGenericAwareResponseTypeName(TypeRef outputType) { + return getNotImplementedString("SurfaceNamer.getGenericAwareResponseType"); + } + + public String getGetResourceListCallName(Field resourcesField) { + return methodName(Name.from("get", resourcesField.getSimpleName(), "list")); + } + + public String getAndSavePagedResponseTypeName(ModelTypeTable typeTable, TypeRef resourceType) { + return getNotImplementedString("SurfaceNamer.getAndSavePagedResponseTypeName"); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/SurfaceTransformerContext.java b/src/main/java/com/google/api/codegen/transformer/SurfaceTransformerContext.java new file mode 100644 index 0000000000..e328f515b1 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/SurfaceTransformerContext.java @@ -0,0 +1,74 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer; + +import com.google.api.codegen.ApiConfig; +import com.google.api.codegen.CollectionConfig; +import com.google.api.codegen.InterfaceConfig; +import com.google.api.codegen.MethodConfig; +import com.google.api.tools.framework.model.Interface; +import com.google.api.tools.framework.model.Method; +import com.google.auto.value.AutoValue; + +import java.util.Collection; + +/** + * The context for transforming a model into a view model for a surface. + */ +@AutoValue +public abstract class SurfaceTransformerContext { + public static SurfaceTransformerContext create( + Interface interfaze, ApiConfig apiConfig, ModelTypeTable typeTable, SurfaceNamer namer) { + return new AutoValue_SurfaceTransformerContext(interfaze, apiConfig, typeTable, namer); + } + + public abstract Interface getInterface(); + + public abstract ApiConfig getApiConfig(); + + public abstract ModelTypeTable getTypeTable(); + + public abstract SurfaceNamer getNamer(); + + public SurfaceTransformerContext withNewTypeTable() { + return create(getInterface(), getApiConfig(), getTypeTable().cloneEmpty(), getNamer()); + } + + public InterfaceConfig getInterfaceConfig() { + return getApiConfig().getInterfaceConfig(getInterface()); + } + + public MethodConfig getMethodConfig(Method method) { + return getInterfaceConfig().getMethodConfig(method); + } + + public Collection getCollectionConfigs() { + return getInterfaceConfig().getCollectionConfigs(); + } + + public CollectionConfig getCollectionConfig(String entityName) { + return getInterfaceConfig().getCollectionConfig(entityName); + } + + public MethodTransformerContext asMethodContext(Method method) { + return MethodTransformerContext.create( + getInterface(), + getApiConfig(), + getTypeTable(), + getNamer(), + method, + getMethodConfig(method)); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/java/JavaGapicSurfaceTransformer.java b/src/main/java/com/google/api/codegen/transformer/java/JavaGapicSurfaceTransformer.java new file mode 100644 index 0000000000..7ddaeda77e --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/java/JavaGapicSurfaceTransformer.java @@ -0,0 +1,340 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer.java; + +import com.google.api.codegen.ApiConfig; +import com.google.api.codegen.InterfaceView; +import com.google.api.codegen.MethodConfig; +import com.google.api.codegen.ServiceConfig; +import com.google.api.codegen.gapic.GapicCodePathMapper; +import com.google.api.codegen.transformer.ApiCallableTransformer; +import com.google.api.codegen.transformer.ApiMethodTransformer; +import com.google.api.codegen.transformer.BundlingTransformer; +import com.google.api.codegen.transformer.MethodTransformerContext; +import com.google.api.codegen.transformer.ModelToViewTransformer; +import com.google.api.codegen.transformer.ModelTypeTable; +import com.google.api.codegen.transformer.PageStreamingTransformer; +import com.google.api.codegen.transformer.PathTemplateTransformer; +import com.google.api.codegen.transformer.ServiceTransformer; +import com.google.api.codegen.transformer.SurfaceNamer; +import com.google.api.codegen.transformer.SurfaceTransformerContext; +import com.google.api.codegen.util.java.JavaTypeTable; +import com.google.api.codegen.viewmodel.ApiMethodType; +import com.google.api.codegen.viewmodel.ApiMethodView; +import com.google.api.codegen.viewmodel.PackageInfoView; +import com.google.api.codegen.viewmodel.RetryCodesDefinitionView; +import com.google.api.codegen.viewmodel.RetryParamsDefinitionView; +import com.google.api.codegen.viewmodel.ServiceDocView; +import com.google.api.codegen.viewmodel.SettingsDocView; +import com.google.api.codegen.viewmodel.StaticApiMethodView; +import com.google.api.codegen.viewmodel.StaticXApiView; +import com.google.api.codegen.viewmodel.StaticXSettingsView; +import com.google.api.codegen.viewmodel.ViewModel; +import com.google.api.gax.core.RetrySettings; +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.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +import io.grpc.Status.Code; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map.Entry; + +/** + * The ModelToViewTransformer to transform a Model into the standard GAPIC surface in Java. + */ +public class JavaGapicSurfaceTransformer implements ModelToViewTransformer { + private GapicCodePathMapper pathMapper; + private ServiceTransformer serviceTransformer; + private PathTemplateTransformer pathTemplateTransformer; + private ApiCallableTransformer apiCallableTransformer; + private ApiMethodTransformer apiMethodTransformer; + private PageStreamingTransformer pageStreamingTransformer; + private BundlingTransformer bundlingTransformer; + + private static final String XAPI_TEMPLATE_FILENAME = "java/main.snip"; + private static final String XSETTINGS_TEMPLATE_FILENAME = "java/settings.snip"; + private static final String PACKAGE_INFO_TEMPLATE_FILENAME = "java/package-info.snip"; + + /** + * Standard constructor. + */ + public JavaGapicSurfaceTransformer(GapicCodePathMapper pathMapper) { + this.pathMapper = pathMapper; + this.serviceTransformer = new ServiceTransformer(); + this.pathTemplateTransformer = new PathTemplateTransformer(); + this.apiCallableTransformer = new ApiCallableTransformer(); + this.apiMethodTransformer = new ApiMethodTransformer(); + this.pageStreamingTransformer = new PageStreamingTransformer(); + this.bundlingTransformer = new BundlingTransformer(); + } + + @Override + public List getTemplateFileNames() { + return Arrays.asList( + XAPI_TEMPLATE_FILENAME, XSETTINGS_TEMPLATE_FILENAME, PACKAGE_INFO_TEMPLATE_FILENAME); + } + + @Override + public List transform(Model model, ApiConfig apiConfig) { + List surfaceDocs = new ArrayList<>(); + SurfaceNamer namer = new JavaSurfaceNamer(); + + List serviceDocs = new ArrayList<>(); + for (Interface service : new InterfaceView().getElementIterable(model)) { + SurfaceTransformerContext context = + SurfaceTransformerContext.create(service, apiConfig, createTypeTable(), namer); + StaticXApiView xapi = generateXApi(context); + surfaceDocs.add(xapi); + + serviceDocs.add(xapi.doc()); + + context = SurfaceTransformerContext.create(service, apiConfig, createTypeTable(), namer); + StaticApiMethodView exampleApiMethod = getExampleApiMethod(xapi.apiMethods()); + StaticXSettingsView xsettings = generateXSettings(context, exampleApiMethod); + surfaceDocs.add(xsettings); + } + + PackageInfoView packageInfo = + generatePackageInfo(model, apiConfig, createTypeTable(), namer, serviceDocs); + surfaceDocs.add(packageInfo); + + return surfaceDocs; + } + + private ModelTypeTable createTypeTable() { + return new ModelTypeTable(new JavaTypeTable(), new JavaModelTypeNameConverter()); + } + + private StaticXApiView generateXApi(SurfaceTransformerContext context) { + addXApiImports(context); + + List methods = generateApiMethods(context); + + StaticXApiView.Builder xapiClass = StaticXApiView.newBuilder(); + + ApiMethodView exampleApiMethod = getExampleApiMethod(methods); + xapiClass.doc(serviceTransformer.generateServiceDoc(context, exampleApiMethod)); + + xapiClass.templateFileName(XAPI_TEMPLATE_FILENAME); + xapiClass.packageName(context.getApiConfig().getPackageName()); + String name = context.getNamer().getApiWrapperClassName(context.getInterface()); + xapiClass.name(name); + xapiClass.settingsClassName(context.getNamer().getApiSettingsClassName(context.getInterface())); + xapiClass.apiCallableMembers(apiCallableTransformer.generateStaticApiCallables(context)); + xapiClass.pathTemplates(pathTemplateTransformer.generatePathTemplates(context)); + xapiClass.formatResourceFunctions( + pathTemplateTransformer.generateFormatResourceFunctions(context)); + xapiClass.parseResourceFunctions( + pathTemplateTransformer.generateParseResourceFunctions(context)); + xapiClass.apiMethods(methods); + + // must be done as the last step to catch all imports + xapiClass.imports(context.getTypeTable().getImports()); + + String outputPath = pathMapper.getOutputPath(context.getInterface(), context.getApiConfig()); + xapiClass.outputPath(outputPath + "/" + name + ".java"); + + return xapiClass.build(); + } + + private StaticApiMethodView getExampleApiMethod(List methods) { + StaticApiMethodView exampleApiMethod = null; + for (StaticApiMethodView method : methods) { + if (method.type().equals(ApiMethodType.FlattenedMethod)) { + exampleApiMethod = method; + break; + } + } + if (exampleApiMethod == null) { + throw new RuntimeException("Could not find flattened method to use as an example method"); + } + return exampleApiMethod; + } + + private StaticXSettingsView generateXSettings( + SurfaceTransformerContext context, StaticApiMethodView exampleApiMethod) { + addXSettingsImports(context); + + StaticXSettingsView.Builder xsettingsClass = StaticXSettingsView.newBuilder(); + xsettingsClass.templateFileName(XSETTINGS_TEMPLATE_FILENAME); + xsettingsClass.packageName(context.getApiConfig().getPackageName()); + xsettingsClass.doc(generateSettingsDoc(context, exampleApiMethod)); + String name = context.getNamer().getApiSettingsClassName(context.getInterface()); + xsettingsClass.name(name); + ServiceConfig serviceConfig = new ServiceConfig(); + xsettingsClass.serviceAddress(serviceConfig.getServiceAddress(context.getInterface())); + xsettingsClass.servicePort(serviceConfig.getServicePort()); + xsettingsClass.authScopes(serviceConfig.getAuthScopes(context.getInterface())); + xsettingsClass.callSettings(apiCallableTransformer.generateCallSettings(context)); + xsettingsClass.pageStreamingDescriptors( + pageStreamingTransformer.generateDescriptorClasses(context)); + xsettingsClass.bundlingDescriptors(bundlingTransformer.generateDescriptorClasses(context)); + xsettingsClass.retryCodesDefinitions(generateRetryCodesDefinitions(context)); + xsettingsClass.retryParamsDefinitions(generateRetryParamsDefinitions(context)); + + // must be done as the last step to catch all imports + xsettingsClass.imports(context.getTypeTable().getImports()); + + String outputPath = pathMapper.getOutputPath(context.getInterface(), context.getApiConfig()); + xsettingsClass.outputPath(outputPath + "/" + name + ".java"); + + return xsettingsClass.build(); + } + + private PackageInfoView generatePackageInfo( + Model model, + ApiConfig apiConfig, + ModelTypeTable createTypeTable, + SurfaceNamer namer, + List serviceDocs) { + PackageInfoView.Builder packageInfo = PackageInfoView.newBuilder(); + + packageInfo.templateFileName(PACKAGE_INFO_TEMPLATE_FILENAME); + + packageInfo.serviceTitle(model.getServiceConfig().getTitle()); + packageInfo.serviceDocs(serviceDocs); + packageInfo.packageName(apiConfig.getPackageName()); + + Interface firstInterface = new InterfaceView().getElementIterable(model).iterator().next(); + String outputPath = pathMapper.getOutputPath(firstInterface, apiConfig); + packageInfo.outputPath(outputPath + "/package-info.java"); + + return packageInfo.build(); + } + + private void addXApiImports(SurfaceTransformerContext context) { + ModelTypeTable typeTable = context.getTypeTable(); + typeTable.saveNicknameFor("com.google.api.gax.grpc.ApiCallable"); + typeTable.saveNicknameFor("com.google.api.gax.protobuf.PathTemplate"); + typeTable.saveNicknameFor("io.grpc.ManagedChannel"); + typeTable.saveNicknameFor("java.io.Closeable"); + typeTable.saveNicknameFor("java.io.IOException"); + typeTable.saveNicknameFor("java.util.ArrayList"); + typeTable.saveNicknameFor("java.util.List"); + typeTable.saveNicknameFor("java.util.concurrent.ScheduledExecutorService"); + } + + private void addXSettingsImports(SurfaceTransformerContext context) { + ModelTypeTable typeTable = context.getTypeTable(); + typeTable.saveNicknameFor("com.google.api.gax.core.ConnectionSettings"); + typeTable.saveNicknameFor("com.google.api.gax.core.RetrySettings"); + typeTable.saveNicknameFor("com.google.api.gax.grpc.ApiCallSettings"); + typeTable.saveNicknameFor("com.google.api.gax.grpc.SimpleCallSettings"); + typeTable.saveNicknameFor("com.google.api.gax.grpc.ServiceApiSettings"); + typeTable.saveNicknameFor("com.google.auth.Credentials"); + typeTable.saveNicknameFor("com.google.common.collect.ImmutableList"); + typeTable.saveNicknameFor("com.google.common.collect.ImmutableMap"); + typeTable.saveNicknameFor("com.google.common.collect.ImmutableSet"); + typeTable.saveNicknameFor("com.google.common.collect.Lists"); + typeTable.saveNicknameFor("com.google.common.collect.Sets"); + typeTable.saveNicknameFor("io.grpc.ManagedChannel"); + typeTable.saveNicknameFor("io.grpc.Status"); + typeTable.saveNicknameFor("org.joda.time.Duration"); + typeTable.saveNicknameFor("java.io.IOException"); + typeTable.saveNicknameFor("java.util.List"); + typeTable.saveNicknameFor("java.util.concurrent.ScheduledExecutorService"); + } + + public SettingsDocView generateSettingsDoc( + SurfaceTransformerContext context, StaticApiMethodView exampleApiMethod) { + SurfaceNamer namer = context.getNamer(); + SettingsDocView.Builder settingsDoc = SettingsDocView.newBuilder(); + ServiceConfig serviceConfig = new ServiceConfig(); + settingsDoc.serviceAddress(serviceConfig.getServiceAddress(context.getInterface())); + settingsDoc.servicePort(serviceConfig.getServicePort()); + settingsDoc.exampleApiMethodName(exampleApiMethod.name()); + settingsDoc.exampleApiMethodSettingsGetter(exampleApiMethod.settingsGetterName()); + settingsDoc.apiClassName(namer.getApiWrapperClassName(context.getInterface())); + settingsDoc.settingsVarName(namer.getApiSettingsVariableName(context.getInterface())); + settingsDoc.settingsClassName(namer.getApiSettingsClassName(context.getInterface())); + settingsDoc.settingsBuilderVarName(namer.getApiSettingsBuilderVarName(context.getInterface())); + return settingsDoc.build(); + } + + private List generateApiMethods(SurfaceTransformerContext context) { + List apiMethods = new ArrayList<>(); + + for (Method method : context.getInterface().getMethods()) { + MethodConfig methodConfig = context.getMethodConfig(method); + MethodTransformerContext methodContext = context.asMethodContext(method); + + if (methodConfig.isPageStreaming()) { + if (methodConfig.isFlattening()) { + for (ImmutableList fields : methodConfig.getFlattening().getFlatteningGroups()) { + apiMethods.add( + apiMethodTransformer.generatePagedFlattenedMethod(methodContext, fields)); + } + } + apiMethods.add(apiMethodTransformer.generatePagedRequestObjectMethod(methodContext)); + apiMethods.add(apiMethodTransformer.generatePagedCallableMethod(methodContext)); + apiMethods.add(apiMethodTransformer.generateUnpagedListCallableMethod(methodContext)); + } else { + if (methodConfig.isFlattening()) { + for (ImmutableList fields : methodConfig.getFlattening().getFlatteningGroups()) { + apiMethods.add(apiMethodTransformer.generateFlattenedMethod(methodContext, fields)); + } + } + apiMethods.add(apiMethodTransformer.generateRequestObjectMethod(methodContext)); + apiMethods.add(apiMethodTransformer.generateCallableMethod(methodContext)); + } + } + + return apiMethods; + } + + private List generateRetryCodesDefinitions( + SurfaceTransformerContext context) { + List definitions = new ArrayList<>(); + + for (Entry> retryCodesDef : + context.getInterfaceConfig().getRetryCodesDefinition().entrySet()) { + definitions.add( + RetryCodesDefinitionView.newBuilder() + .key(retryCodesDef.getKey()) + .codes(retryCodesDef.getValue()) + .build()); + } + + return definitions; + } + + private List generateRetryParamsDefinitions( + SurfaceTransformerContext context) { + List definitions = new ArrayList<>(); + + for (Entry retryCodesDef : + context.getInterfaceConfig().getRetrySettingsDefinition().entrySet()) { + RetrySettings settings = retryCodesDef.getValue(); + RetryParamsDefinitionView.Builder params = RetryParamsDefinitionView.newBuilder(); + params.key(retryCodesDef.getKey()); + params.initialRetryDelay(settings.getInitialRetryDelay()); + params.retryDelayMultiplier(settings.getRetryDelayMultiplier()); + params.maxRetryDelay(settings.getMaxRetryDelay()); + params.initialRpcTimeout(settings.getInitialRpcTimeout()); + params.rpcTimeoutMultiplier(settings.getRpcTimeoutMultiplier()); + params.maxRpcTimeout(settings.getMaxRpcTimeout()); + params.totalTimeout(settings.getTotalTimeout()); + definitions.add(params.build()); + } + + return definitions; + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/java/JavaModelTypeNameConverter.java b/src/main/java/com/google/api/codegen/transformer/java/JavaModelTypeNameConverter.java new file mode 100644 index 0000000000..2f2e1e4ae5 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/java/JavaModelTypeNameConverter.java @@ -0,0 +1,236 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer.java; + +import com.google.api.codegen.LanguageUtil; +import com.google.api.codegen.transformer.ModelTypeNameConverter; +import com.google.api.codegen.util.TypeName; +import com.google.api.codegen.util.TypeNameConverter; +import com.google.api.codegen.util.TypedValue; +import com.google.api.codegen.util.java.JavaTypeTable; +import com.google.api.tools.framework.model.ProtoElement; +import com.google.api.tools.framework.model.ProtoFile; +import com.google.api.tools.framework.model.TypeRef; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import com.google.common.io.Files; +import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type; + +import java.io.File; + +/** + * The ModelTypeTable for Java. + */ +public class JavaModelTypeNameConverter implements ModelTypeNameConverter { + + /** + * The package prefix protoc uses if no java package option was provided. + */ + private static final String DEFAULT_JAVA_PACKAGE_PREFIX = "com.google.protos"; + + /** + * A map from primitive types in proto to Java counterparts. + */ + private static final ImmutableMap PRIMITIVE_TYPE_MAP = + ImmutableMap.builder() + .put(Type.TYPE_BOOL, "boolean") + .put(Type.TYPE_DOUBLE, "double") + .put(Type.TYPE_FLOAT, "float") + .put(Type.TYPE_INT64, "long") + .put(Type.TYPE_UINT64, "long") + .put(Type.TYPE_SINT64, "long") + .put(Type.TYPE_FIXED64, "long") + .put(Type.TYPE_SFIXED64, "long") + .put(Type.TYPE_INT32, "int") + .put(Type.TYPE_UINT32, "int") + .put(Type.TYPE_SINT32, "int") + .put(Type.TYPE_FIXED32, "int") + .put(Type.TYPE_SFIXED32, "int") + .put(Type.TYPE_STRING, "java.lang.String") + .put(Type.TYPE_BYTES, "com.google.protobuf.ByteString") + .build(); + + /** + * A map from primitive types in proto to zero value in Java + */ + private static final ImmutableMap PRIMITIVE_ZERO_VALUE = + ImmutableMap.builder() + .put(Type.TYPE_BOOL, "false") + .put(Type.TYPE_DOUBLE, "0.0") + .put(Type.TYPE_FLOAT, "0.0F") + .put(Type.TYPE_INT64, "0L") + .put(Type.TYPE_UINT64, "0L") + .put(Type.TYPE_SINT64, "0L") + .put(Type.TYPE_FIXED64, "0L") + .put(Type.TYPE_SFIXED64, "0L") + .put(Type.TYPE_INT32, "0") + .put(Type.TYPE_UINT32, "0") + .put(Type.TYPE_SINT32, "0") + .put(Type.TYPE_FIXED32, "0") + .put(Type.TYPE_SFIXED32, "0") + .put(Type.TYPE_STRING, "\"\"") + .put(Type.TYPE_BYTES, "ByteString.copyFromUtf8(\"\")") + .build(); + + private TypeNameConverter typeNameConverter; + + /** + * Standard constructor. + */ + public JavaModelTypeNameConverter() { + this.typeNameConverter = new JavaTypeTable(); + } + + @Override + public TypeName getTypeName(TypeRef type) { + if (type.isMap()) { + TypeName mapTypeName = typeNameConverter.getTypeName("java.util.Map"); + TypeName keyTypeName = getTypeNameForElementType(type.getMapKeyField().getType(), true); + TypeName valueTypeName = getTypeNameForElementType(type.getMapValueField().getType(), true); + return new TypeName( + mapTypeName.getFullName(), + mapTypeName.getNickname(), + "%s<%i, %i>", + keyTypeName, + valueTypeName); + } else if (type.isRepeated()) { + TypeName listTypeName = typeNameConverter.getTypeName("java.util.List"); + TypeName elementTypeName = getTypeNameForElementType(type, true); + return new TypeName( + listTypeName.getFullName(), listTypeName.getNickname(), "%s<%i>", elementTypeName); + } else { + return getTypeNameForElementType(type, false); + } + } + + @Override + public TypeName getTypeNameForElementType(TypeRef type) { + return getTypeNameForElementType(type, true); + } + + /** + * Returns the Java representation of a type, without cardinality. If the type is a Java + * primitive, basicTypeName returns it in unboxed form. + */ + private TypeName getTypeNameForElementType(TypeRef type, boolean shouldBoxPrimitives) { + String primitiveTypeName = PRIMITIVE_TYPE_MAP.get(type.getKind()); + if (primitiveTypeName != null) { + if (primitiveTypeName.contains(".")) { + // Fully qualified type name, use regular type name resolver. Can skip boxing logic + // because those types are already boxed. + return typeNameConverter.getTypeName(primitiveTypeName); + } else { + if (shouldBoxPrimitives) { + return new TypeName(JavaTypeTable.getBoxedTypeName(primitiveTypeName)); + } else { + return new TypeName(primitiveTypeName); + } + } + } + switch (type.getKind()) { + case TYPE_MESSAGE: + return getTypeName(type.getMessageType()); + case TYPE_ENUM: + return getTypeName(type.getEnumType()); + default: + throw new IllegalArgumentException("unknown type kind: " + type.getKind()); + } + } + + @Override + public String renderPrimitiveValue(TypeRef type, String value) { + Type primitiveType = type.getKind(); + if (!PRIMITIVE_TYPE_MAP.containsKey(primitiveType)) { + throw new IllegalArgumentException( + "Initial values are only supported for primitive types, got type " + + type + + ", with value " + + value); + } + switch (primitiveType) { + case TYPE_BOOL: + return value.toLowerCase(); + case TYPE_FLOAT: + return value + "F"; + case TYPE_INT64: + case TYPE_UINT64: + return value + "L"; + case TYPE_STRING: + return "\"" + value + "\""; + case TYPE_BYTES: + return "ByteString.copyFromUtf8(\"" + value + "\")"; + default: + // Types that do not need to be modified (e.g. TYPE_INT32) are handled here + return value; + } + } + + /** + * Returns the Java representation of a zero value for that type, to be used in code sample doc. + * + * Parametric types may use the diamond operator, since the return value will be used only in + * initialization. + */ + @Override + public TypedValue getZeroValue(TypeRef type) { + // Don't call importAndGetShortestName; we don't need to import these. + if (type.isMap()) { + return TypedValue.create(typeNameConverter.getTypeName("java.util.HashMap"), "new %s<>()"); + } + if (type.isRepeated()) { + return TypedValue.create(typeNameConverter.getTypeName("java.util.ArrayList"), "new %s<>()"); + } + if (PRIMITIVE_ZERO_VALUE.containsKey(type.getKind())) { + return TypedValue.create(getTypeName(type), PRIMITIVE_ZERO_VALUE.get(type.getKind())); + } + if (type.isMessage()) { + return TypedValue.create(getTypeName(type), "%s.newBuilder().build()"); + } + return TypedValue.create(new TypeName(""), "null"); + } + + @Override + public TypeName getTypeName(ProtoElement elem) { + // Construct the full name in Java + String name = getJavaPackage(elem.getFile()); + if (!elem.getFile().getProto().getOptions().getJavaMultipleFiles()) { + String outerClassName = elem.getFile().getProto().getOptions().getJavaOuterClassname(); + if (outerClassName.isEmpty()) { + outerClassName = getFileClassName(elem.getFile()); + } + name = name + "." + outerClassName; + } + String shortName = elem.getFullName().substring(elem.getFile().getFullName().length() + 1); + name = name + "." + shortName; + + return new TypeName(name, shortName); + } + + private static String getJavaPackage(ProtoFile file) { + String packageName = file.getProto().getOptions().getJavaPackage(); + if (Strings.isNullOrEmpty(packageName)) { + return DEFAULT_JAVA_PACKAGE_PREFIX + "." + file.getFullName(); + } + return packageName; + } + + /** + * Gets the class name for the given proto file. + */ + private static String getFileClassName(ProtoFile file) { + String baseName = Files.getNameWithoutExtension(new File(file.getSimpleName()).getName()); + return LanguageUtil.lowerUnderscoreToUpperCamel(baseName); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/java/JavaSurfaceNamer.java b/src/main/java/com/google/api/codegen/transformer/java/JavaSurfaceNamer.java new file mode 100644 index 0000000000..6e5d6d7c13 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/java/JavaSurfaceNamer.java @@ -0,0 +1,103 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer.java; + +import com.google.api.codegen.MethodConfig; +import com.google.api.codegen.ServiceMessages; +import com.google.api.codegen.transformer.ModelTypeFormatterImpl; +import com.google.api.codegen.transformer.ModelTypeTable; +import com.google.api.codegen.transformer.SurfaceNamer; +import com.google.api.codegen.util.java.JavaNameFormatter; +import com.google.api.codegen.util.java.JavaRenderingUtil; +import com.google.api.codegen.util.java.JavaTypeTable; +import com.google.api.tools.framework.model.Method; +import com.google.api.tools.framework.model.TypeRef; + +import java.util.Arrays; +import java.util.List; + +/** + * The SurfaceNamer for Java. + */ +public class JavaSurfaceNamer extends SurfaceNamer { + + /** + * Standard constructor. + */ + public JavaSurfaceNamer() { + super( + new JavaNameFormatter(), + new ModelTypeFormatterImpl(new JavaModelTypeNameConverter()), + new JavaTypeTable()); + } + + @Override + public List getDocLines(String text) { + return JavaRenderingUtil.getDocLines(text); + } + + @Override + public List getThrowsDocLines() { + return Arrays.asList("@throws com.google.api.gax.grpc.ApiException if the remote call fails"); + } + + @Override + public void addPageStreamingDescriptorImports(ModelTypeTable typeTable) { + typeTable.saveNicknameFor("com.google.api.gax.grpc.PageStreamingDescriptor"); + } + + @Override + public void addBundlingDescriptorImports(ModelTypeTable typeTable) { + typeTable.saveNicknameFor("com.google.api.gax.grpc.BundlingDescriptor"); + typeTable.saveNicknameFor("com.google.api.gax.grpc.RequestIssuer"); + typeTable.saveNicknameFor("java.util.ArrayList"); + typeTable.saveNicknameFor("java.util.Collection"); + } + + @Override + public void addPageStreamingCallSettingsImports(ModelTypeTable typeTable) { + typeTable.saveNicknameFor("com.google.api.gax.grpc.PageStreamingCallSettings"); + } + + @Override + public void addBundlingCallSettingsImports(ModelTypeTable typeTable) { + typeTable.saveNicknameFor("com.google.api.gax.grpc.BundlingCallSettings"); + typeTable.saveNicknameFor("com.google.api.gax.grpc.BundlingSettings"); + } + + @Override + public String getStaticReturnTypeName(Method method, MethodConfig methodConfig) { + if (ServiceMessages.s_isEmptyType(method.getOutputType())) { + return "void"; + } + return getModelTypeFormatter().getFullNameFor(method.getOutputType()); + } + + @Override + public String getGenericAwareResponseTypeName(TypeRef outputType) { + if (ServiceMessages.s_isEmptyType(outputType)) { + return "Void"; + } else { + return getModelTypeFormatter().getFullNameFor(outputType); + } + } + + @Override + public String getAndSavePagedResponseTypeName(ModelTypeTable typeTable, TypeRef resourceType) { + String resourceTypeName = typeTable.getFullNameForElementType(resourceType); + return typeTable.getAndSaveNicknameForContainer( + "com.google.api.gax.core.PageAccessor", resourceTypeName); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/php/PhpGapicSurfaceTransformer.java b/src/main/java/com/google/api/codegen/transformer/php/PhpGapicSurfaceTransformer.java new file mode 100644 index 0000000000..c0dc30c110 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/php/PhpGapicSurfaceTransformer.java @@ -0,0 +1,166 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer.php; + +import com.google.api.codegen.ApiConfig; +import com.google.api.codegen.InterfaceView; +import com.google.api.codegen.ServiceConfig; +import com.google.api.codegen.gapic.GapicCodePathMapper; +import com.google.api.codegen.transformer.ApiMethodTransformer; +import com.google.api.codegen.transformer.ModelToViewTransformer; +import com.google.api.codegen.transformer.ModelTypeTable; +import com.google.api.codegen.transformer.PageStreamingTransformer; +import com.google.api.codegen.transformer.PathTemplateTransformer; +import com.google.api.codegen.transformer.ServiceTransformer; +import com.google.api.codegen.transformer.SurfaceNamer; +import com.google.api.codegen.transformer.SurfaceTransformerContext; +import com.google.api.codegen.util.php.PhpTypeTable; +import com.google.api.codegen.viewmodel.ApiMethodView; +import com.google.api.codegen.viewmodel.DynamicXApiView; +import com.google.api.codegen.viewmodel.ViewModel; +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 java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * The ModelToViewTransformer to transform a Model into the standard GAPIC surface in PHP. + */ +public class PhpGapicSurfaceTransformer implements ModelToViewTransformer { + private GapicCodePathMapper pathMapper; + private ServiceTransformer serviceTransformer; + private PathTemplateTransformer pathTemplateTransformer; + private PageStreamingTransformer pageStreamingTransformer; + private ApiMethodTransformer apiMethodTransformer; + + private static final String XAPI_TEMPLATE_FILENAME = "php/main.snip"; + + /** + * Standard constructor. + */ + public PhpGapicSurfaceTransformer(ApiConfig apiConfig, GapicCodePathMapper pathMapper) { + this.pathMapper = pathMapper; + this.serviceTransformer = new ServiceTransformer(); + this.pathTemplateTransformer = new PathTemplateTransformer(); + this.pageStreamingTransformer = new PageStreamingTransformer(); + this.apiMethodTransformer = new ApiMethodTransformer(); + } + + @Override + public List getTemplateFileNames() { + return Arrays.asList(XAPI_TEMPLATE_FILENAME); + } + + @Override + public List transform(Model model, ApiConfig apiConfig) { + List surfaceDocs = new ArrayList<>(); + for (Interface service : new InterfaceView().getElementIterable(model)) { + ModelTypeTable modelTypeTable = + new ModelTypeTable(new PhpTypeTable(), new PhpModelTypeNameConverter()); + SurfaceTransformerContext context = + SurfaceTransformerContext.create( + service, apiConfig, modelTypeTable, new PhpSurfaceNamer()); + + surfaceDocs.addAll(transform(context)); + } + return surfaceDocs; + } + + public List transform(SurfaceTransformerContext context) { + String outputPath = pathMapper.getOutputPath(context.getInterface(), context.getApiConfig()); + SurfaceNamer namer = context.getNamer(); + + List surfaceData = new ArrayList<>(); + + addXApiImports(context); + + List methods = generateApiMethods(context); + + DynamicXApiView.Builder xapiClass = DynamicXApiView.newBuilder(); + + xapiClass.doc(serviceTransformer.generateServiceDoc(context, methods.get(0))); + + xapiClass.templateFileName(XAPI_TEMPLATE_FILENAME); + xapiClass.protoFilename(context.getInterface().getFile().getSimpleName()); + xapiClass.packageName(context.getApiConfig().getPackageName()); + String name = namer.getApiWrapperClassName(context.getInterface()); + xapiClass.name(name); + ServiceConfig serviceConfig = new ServiceConfig(); + xapiClass.serviceAddress(serviceConfig.getServiceAddress(context.getInterface())); + xapiClass.servicePort(serviceConfig.getServicePort()); + xapiClass.serviceTitle(serviceConfig.getTitle(context.getInterface())); + xapiClass.authScopes(serviceConfig.getAuthScopes(context.getInterface())); + + xapiClass.pathTemplates(pathTemplateTransformer.generatePathTemplates(context)); + xapiClass.formatResourceFunctions( + pathTemplateTransformer.generateFormatResourceFunctions(context)); + xapiClass.parseResourceFunctions( + pathTemplateTransformer.generateParseResourceFunctions(context)); + xapiClass.pathTemplateGetterFunctions( + pathTemplateTransformer.generatePathTemplateGetterFunctions(context)); + xapiClass.pageStreamingDescriptors(pageStreamingTransformer.generateDescriptors(context)); + + xapiClass.methodKeys(generateMethodKeys(context)); + xapiClass.clientConfigPath(namer.getClientConfigPath(context.getInterface())); + xapiClass.interfaceKey(context.getInterface().getFullName()); + String grpcClientTypeName = namer.getGrpcClientTypeName(context.getInterface()); + xapiClass.grpcClientTypeName(context.getTypeTable().getAndSaveNicknameFor(grpcClientTypeName)); + + xapiClass.apiMethods(methods); + + // must be done as the last step to catch all imports + xapiClass.imports(context.getTypeTable().getImports()); + + xapiClass.outputPath(outputPath + "/" + name + ".php"); + + surfaceData.add(xapiClass.build()); + + return surfaceData; + } + + private void addXApiImports(SurfaceTransformerContext context) { + ModelTypeTable typeTable = context.getTypeTable(); + typeTable.saveNicknameFor("Google\\GAX\\AgentHeaderDescriptor"); + typeTable.saveNicknameFor("Google\\GAX\\ApiCallable"); + typeTable.saveNicknameFor("Google\\GAX\\CallSettings"); + typeTable.saveNicknameFor("Google\\GAX\\GrpcBootstrap"); + typeTable.saveNicknameFor("Google\\GAX\\GrpcConstants"); + typeTable.saveNicknameFor("Google\\GAX\\PathTemplate"); + } + + private List generateMethodKeys(SurfaceTransformerContext context) { + List methodKeys = new ArrayList<>(); + + for (Method method : context.getInterface().getMethods()) { + methodKeys.add(context.getNamer().getMethodKey(method)); + } + + return methodKeys; + } + + private List generateApiMethods(SurfaceTransformerContext context) { + List apiMethods = new ArrayList<>(); + + for (Method method : context.getInterface().getMethods()) { + apiMethods.add( + apiMethodTransformer.generateOptionalArrayMethod(context.asMethodContext(method))); + } + + return apiMethods; + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/php/PhpModelTypeNameConverter.java b/src/main/java/com/google/api/codegen/transformer/php/PhpModelTypeNameConverter.java new file mode 100644 index 0000000000..89244d6262 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/php/PhpModelTypeNameConverter.java @@ -0,0 +1,173 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer.php; + +import com.google.api.codegen.transformer.ModelTypeNameConverter; +import com.google.api.codegen.util.TypeName; +import com.google.api.codegen.util.TypeNameConverter; +import com.google.api.codegen.util.TypedValue; +import com.google.api.codegen.util.php.PhpTypeTable; +import com.google.api.tools.framework.model.ProtoElement; +import com.google.api.tools.framework.model.ProtoFile; +import com.google.api.tools.framework.model.TypeRef; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type; + +public class PhpModelTypeNameConverter implements ModelTypeNameConverter { + + /** + * A map from primitive types in proto to PHP counterparts. + */ + private static final ImmutableMap PRIMITIVE_TYPE_MAP = + ImmutableMap.builder() + .put(Type.TYPE_BOOL, "bool") + .put(Type.TYPE_DOUBLE, "float") + .put(Type.TYPE_FLOAT, "float") + .put(Type.TYPE_INT64, "int") + .put(Type.TYPE_UINT64, "int") + .put(Type.TYPE_SINT64, "int") + .put(Type.TYPE_FIXED64, "int") + .put(Type.TYPE_SFIXED64, "int") + .put(Type.TYPE_INT32, "int") + .put(Type.TYPE_UINT32, "int") + .put(Type.TYPE_SINT32, "int") + .put(Type.TYPE_FIXED32, "int") + .put(Type.TYPE_SFIXED32, "int") + .put(Type.TYPE_STRING, "string") + .put(Type.TYPE_BYTES, "string") + .build(); + + /** + * A map from primitive types in proto to zero value in PHP + */ + private static final ImmutableMap PRIMITIVE_ZERO_VALUE = + ImmutableMap.builder() + .put(Type.TYPE_BOOL, "false") + .put(Type.TYPE_DOUBLE, "0.0") + .put(Type.TYPE_FLOAT, "0.0") + .put(Type.TYPE_INT64, "0") + .put(Type.TYPE_UINT64, "0") + .put(Type.TYPE_SINT64, "0") + .put(Type.TYPE_FIXED64, "0") + .put(Type.TYPE_SFIXED64, "0") + .put(Type.TYPE_INT32, "0") + .put(Type.TYPE_UINT32, "0") + .put(Type.TYPE_SINT32, "0") + .put(Type.TYPE_FIXED32, "0") + .put(Type.TYPE_SFIXED32, "0") + .put(Type.TYPE_STRING, "\"\"") + .put(Type.TYPE_BYTES, "\"\"") + .build(); + + private TypeNameConverter typeNameConverter; + + public PhpModelTypeNameConverter() { + this.typeNameConverter = new PhpTypeTable(); + } + + @Override + public TypeName getTypeName(TypeRef type) { + if (type.isMap()) { + return new TypeName("array"); + } else if (type.isRepeated()) { + TypeName elementTypeName = getTypeNameForElementType(type); + return new TypeName("", "", "%i[]", elementTypeName); + } else { + return getTypeNameForElementType(type); + } + } + + /** + * Returns the PHP representation of a type, without cardinality. If the type is a primitive, + * getTypeNameForElementType returns it in unboxed form. + */ + @Override + public TypeName getTypeNameForElementType(TypeRef type) { + String primitiveTypeName = PRIMITIVE_TYPE_MAP.get(type.getKind()); + if (primitiveTypeName != null) { + if (primitiveTypeName.contains("\\")) { + // Fully qualified type name, use regular type name resolver. Can skip boxing logic + // because those types are already boxed. + return typeNameConverter.getTypeName(primitiveTypeName); + } else { + return new TypeName(primitiveTypeName); + } + } + switch (type.getKind()) { + case TYPE_MESSAGE: + return getTypeName(type.getMessageType()); + case TYPE_ENUM: + return getTypeName(type.getEnumType()); + default: + throw new IllegalArgumentException("unknown type kind: " + type.getKind()); + } + } + + @Override + public TypeName getTypeName(ProtoElement elem) { + return typeNameConverter.getTypeName(elem.getFullName().replaceAll("\\.", "\\\\")); + } + + /** + * Returns the PHP representation of a zero value for that type, to be used in code sample doc. + */ + @Override + public TypedValue getZeroValue(TypeRef type) { + // Don't call getTypeName; we don't need to import these. + if (type.isMap()) { + return TypedValue.create(new TypeName("array"), "[]"); + } + if (type.isRepeated()) { + return TypedValue.create(new TypeName("array"), "[]"); + } + if (PRIMITIVE_ZERO_VALUE.containsKey(type.getKind())) { + return TypedValue.create(getTypeName(type), PRIMITIVE_ZERO_VALUE.get(type.getKind())); + } + if (type.isMessage()) { + return TypedValue.create(getTypeName(type), "new %s()"); + } + return TypedValue.create(new TypeName(""), "null"); + } + + @Override + public String renderPrimitiveValue(TypeRef type, String value) { + Type primitiveType = type.getKind(); + if (!PRIMITIVE_TYPE_MAP.containsKey(primitiveType)) { + throw new IllegalArgumentException( + "Initial values are only supported for primitive types, got type " + + type + + ", with value " + + value); + } + switch (primitiveType) { + case TYPE_BOOL: + return value.toLowerCase(); + case TYPE_STRING: + case TYPE_BYTES: + return "\"" + value + "\""; + default: + // Types that do not need to be modified (e.g. TYPE_INT32) are handled + // here + return value; + } + } + + /** + * Gets the PHP package for the given proto file. + */ + private static String getPhpPackage(ProtoFile file) { + return file.getProto().getPackage().replaceAll("\\.", "\\\\"); + } +} diff --git a/src/main/java/com/google/api/codegen/transformer/php/PhpSurfaceNamer.java b/src/main/java/com/google/api/codegen/transformer/php/PhpSurfaceNamer.java new file mode 100644 index 0000000000..4561806332 --- /dev/null +++ b/src/main/java/com/google/api/codegen/transformer/php/PhpSurfaceNamer.java @@ -0,0 +1,93 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.transformer.php; + +import com.google.api.codegen.CollectionConfig; +import com.google.api.codegen.MethodConfig; +import com.google.api.codegen.ServiceMessages; +import com.google.api.codegen.transformer.ModelTypeFormatterImpl; +import com.google.api.codegen.transformer.ModelTypeTable; +import com.google.api.codegen.transformer.SurfaceNamer; +import com.google.api.codegen.util.Name; +import com.google.api.codegen.util.php.PhpNameFormatter; +import com.google.api.codegen.util.php.PhpTypeTable; +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.TypeRef; + +/** + * The SurfaceNamer for PHP. + */ +public class PhpSurfaceNamer extends SurfaceNamer { + public PhpSurfaceNamer() { + super( + new PhpNameFormatter(), + new ModelTypeFormatterImpl(new PhpModelTypeNameConverter()), + new PhpTypeTable()); + } + + @Override + public String getSetFunctionCallName(TypeRef type, Name identifier) { + if (type.isMap() || type.isRepeated()) { + return methodName(Name.from("add").join(identifier)); + } else { + return methodName(Name.from("set").join(identifier)); + } + } + + @Override + public String getPathTemplateName(CollectionConfig collectionConfig) { + return inittedConstantName(Name.from(collectionConfig.getEntityName(), "name", "template")); + } + + @Override + public void addPageStreamingDescriptorImports(ModelTypeTable typeTable) { + typeTable.saveNicknameFor("Google\\GAX\\PageStreamingDescriptor"); + } + + @Override + public String getClientConfigPath(Interface service) { + return "./resources/" + + Name.upperCamel(service.getSimpleName()).join("client_config").toLowerUnderscore() + + ".json"; + } + + @Override + public boolean shouldImportRequestObjectParamType(Field field) { + return field.getType().isMap(); + } + + @Override + public String getRetrySettingsTypeName() { + return "Google\\GAX\\RetrySettings"; + } + + @Override + public String getOptionalArrayTypeName() { + return "array"; + } + + @Override + public String getDynamicReturnTypeName(Method method, MethodConfig methodConfig) { + if (new ServiceMessages().isEmptyType(method.getOutputType())) { + return ""; + } + if (methodConfig.isPageStreaming()) { + return "Google\\GAX\\PageAccessor"; + } + return getModelTypeFormatter().getFullNameFor(method.getOutputType()); + } +} diff --git a/src/main/java/com/google/api/codegen/util/CommonRenderingUtil.java b/src/main/java/com/google/api/codegen/util/CommonRenderingUtil.java new file mode 100644 index 0000000000..1971b7c7a7 --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/CommonRenderingUtil.java @@ -0,0 +1,36 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util; + +import com.google.common.base.Splitter; + +import java.util.ArrayList; +import java.util.List; + +/** + * Utility class to process text in the templates. + */ +public class CommonRenderingUtil { + + public static List getDocLines(String text) { + // TODO: convert markdown to language-specific doc format + // https://github.com/googleapis/toolkit/issues/331 + List result = new ArrayList<>(); + for (String line : Splitter.on(String.format("%n")).split(text)) { + result.add(line); + } + return result; + } +} diff --git a/src/main/java/com/google/api/codegen/util/Name.java b/src/main/java/com/google/api/codegen/util/Name.java new file mode 100644 index 0000000000..8336f17260 --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/Name.java @@ -0,0 +1,204 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util; + +import com.google.api.client.util.Joiner; +import com.google.common.base.CaseFormat; + +import java.util.ArrayList; +import java.util.List; + +/** + * Name represents an identifier name which is casing-aware. + */ +public class Name { + private List namePieces; + + /** + * Creates a Name from a sequence of lower-underscore strings. + * + * @throws IllegalArgumentException if any of the strings contain any characters that are not + * lower case or underscores. + */ + public static Name from(String... pieces) { + List namePieces = new ArrayList<>(); + for (String piece : pieces) { + validateLowerUnderscore(piece); + namePieces.add(new NamePiece(piece, CaseFormat.LOWER_UNDERSCORE)); + } + return new Name(namePieces); + } + + /** + * Creates a Name from a sequence of lower-camel strings. + * + * @throws IllegalArgumentException if any of the strings do not follow the lower-camel format. + */ + public static Name lowerCamel(String... pieces) { + List namePieces = new ArrayList<>(); + for (String piece : pieces) { + validateCamel(piece, false); + namePieces.add(new NamePiece(piece, CaseFormat.LOWER_CAMEL)); + } + return new Name(namePieces); + } + + /** + * Creates a Name from a sequence of upper-camel strings. + * + * @throws IllegalArgumentException if any of the strings do not follow the upper-camel format. + */ + public static Name upperCamel(String... pieces) { + List namePieces = new ArrayList<>(); + for (String piece : pieces) { + validateCamel(piece, true); + namePieces.add(new NamePiece(piece, CaseFormat.UPPER_CAMEL)); + } + return new Name(namePieces); + } + + private static void validateLowerUnderscore(String identifier) { + if (!isLowerUnderscore(identifier)) { + throw new IllegalArgumentException( + "Name: identifier not in lower-underscore: '" + identifier + "'"); + } + } + + private static boolean isLowerUnderscore(String identifier) { + Character underscore = Character.valueOf('_'); + for (Character ch : identifier.toCharArray()) { + if (!Character.isLowerCase(ch) && !ch.equals(underscore) && !Character.isDigit(ch)) { + return false; + } + } + return true; + } + + private static void validateCamel(String identifier, boolean upper) { + if (!isCamel(identifier, upper)) { + String casingDescription = "lower camel"; + if (upper) { + casingDescription = "upper camel"; + } + throw new IllegalArgumentException( + "Name: identifier not in " + casingDescription + ": '" + identifier + "'"); + } + } + + private static boolean isCamel(String identifier, boolean upper) { + if (identifier.length() == 0) { + return true; + } + if (upper && !Character.isUpperCase(identifier.charAt(0))) { + return false; + } + if (!upper && !Character.isLowerCase(identifier.charAt(0))) { + return false; + } + for (Character ch : identifier.toCharArray()) { + if (!Character.isLowerCase(ch) && !Character.isUpperCase(ch)) { + return false; + } + } + return true; + } + + private Name(List namePieces) { + this.namePieces = namePieces; + } + + /** + * Returns the identifier in upper-underscore format. + */ + public String toUpperUnderscore() { + return toUnderscore(CaseFormat.UPPER_UNDERSCORE); + } + + /** + * Returns the identifier in lower-underscore format. + */ + public String toLowerUnderscore() { + return toUnderscore(CaseFormat.LOWER_UNDERSCORE); + } + + private String toUnderscore(CaseFormat caseFormat) { + List newPieces = new ArrayList<>(); + for (NamePiece namePiece : namePieces) { + newPieces.add(namePiece.caseFormat.to(caseFormat, namePiece.identifier)); + } + return Joiner.on('_').join(newPieces); + } + + /** + * Returns the identifier in lower-camel format. + */ + public String toLowerCamel() { + return toCamel(CaseFormat.LOWER_CAMEL); + } + + /** + * Returns the identifier in upper-camel format. + */ + public String toUpperCamel() { + return toCamel(CaseFormat.UPPER_CAMEL); + } + + private String toCamel(CaseFormat caseFormat) { + StringBuffer buffer = new StringBuffer(); + boolean firstPiece = true; + for (NamePiece namePiece : namePieces) { + if (firstPiece && caseFormat.equals(CaseFormat.LOWER_CAMEL)) { + buffer.append(namePiece.caseFormat.to(CaseFormat.LOWER_CAMEL, namePiece.identifier)); + } else { + buffer.append(namePiece.caseFormat.to(CaseFormat.UPPER_CAMEL, namePiece.identifier)); + } + firstPiece = false; + } + return buffer.toString(); + } + + /** + * Returns a new Name containing the pieces from this Name plus the given + * identifier added on the end. + */ + public Name join(String identifier) { + validateLowerUnderscore(identifier); + List newPieceList = new ArrayList<>(); + newPieceList.addAll(namePieces); + newPieceList.add(new NamePiece(identifier, CaseFormat.LOWER_UNDERSCORE)); + return new Name(newPieceList); + } + + /** + * Returns a new Name containing the pieces from this Name plus the pieces of the given + * name added on the end. + */ + public Name join(Name rhs) { + List newPieceList = new ArrayList<>(); + newPieceList.addAll(namePieces); + newPieceList.addAll(rhs.namePieces); + return new Name(newPieceList); + } + + private static class NamePiece { + public final String identifier; + public final CaseFormat caseFormat; + + private NamePiece(String identifier, CaseFormat caseFormat) { + this.identifier = identifier; + this.caseFormat = caseFormat; + } + } +} diff --git a/src/main/java/com/google/api/codegen/util/NameFormatter.java b/src/main/java/com/google/api/codegen/util/NameFormatter.java new file mode 100644 index 0000000000..4b394a284b --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/NameFormatter.java @@ -0,0 +1,66 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util; + +/** + * A NameFormatter formats Name objects in using the casing scheme for + * a particular type of identifier in a particular programming language. + */ +public interface NameFormatter { + + /** + * Formats the name as a class name. + */ + String className(Name name); + + /** + * Formats the name as a variable name. + */ + String varName(Name name); + + /** + * Formats the name as a reference to a variable name. + */ + String varReference(Name name); + + /** + * Formats the name as a method name. + */ + String methodName(Name name); + + /** + * Formats the name as a static function name. + */ + String staticFunctionName(Name name); + + /** + * Formats the name as a constant which requires initialization. + * + * It may seem odd that the initialization aspect needs to be distinguished, + * but this is relevant in PHP, where constants with non-trivial initialization + * have to be initialized on first use instead of at declaration time. + */ + String inittedConstantName(Name name); + + /** + * Formats the name as a key name, to be used as a key in a map or hash table. + */ + String keyName(Name name); + + /** + * Formats the name path as a qualified name. + */ + String qualifiedName(NamePath namePath); +} diff --git a/src/main/java/com/google/api/codegen/util/NameFormatterDelegator.java b/src/main/java/com/google/api/codegen/util/NameFormatterDelegator.java new file mode 100644 index 0000000000..40c1cfb12f --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/NameFormatterDelegator.java @@ -0,0 +1,74 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util; + +/** + * NameFormatterDelegator is an abstract class that implements the NameFormatter + * interface and simply delegates calls to another NameFormatter. This allows a + * child class to provide the interface of NameFormatter along with additional + * functionality. + * + * Note to future maintainers: This class should only contain methods which + * forward on to NameFormatter and nothing else; otherwise, it is no longer + * functioning in spirit as a mix-in. + */ +public abstract class NameFormatterDelegator implements NameFormatter { + + private NameFormatter formatter; + + public NameFormatterDelegator(NameFormatter formatter) { + this.formatter = formatter; + } + + @Override + public String className(Name name) { + return formatter.className(name); + } + + @Override + public String varName(Name name) { + return formatter.varName(name); + } + + @Override + public String varReference(Name name) { + return formatter.varReference(name); + } + + @Override + public String methodName(Name name) { + return formatter.methodName(name); + } + + @Override + public String staticFunctionName(Name name) { + return formatter.staticFunctionName(name); + } + + @Override + public String inittedConstantName(Name name) { + return formatter.inittedConstantName(name); + } + + @Override + public String keyName(Name name) { + return formatter.keyName(name); + } + + @Override + public String qualifiedName(NamePath namePath) { + return formatter.qualifiedName(namePath); + } +} diff --git a/src/main/java/com/google/api/codegen/util/NamePath.java b/src/main/java/com/google/api/codegen/util/NamePath.java new file mode 100644 index 0000000000..b34c3a4276 --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/NamePath.java @@ -0,0 +1,88 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util; + +import com.google.common.base.Joiner; + +import java.util.ArrayList; +import java.util.List; + +/** + * NamePath represents a fully-qualified name, separated by something like + * dots or slashes. + */ +public class NamePath { + private List pathPieces; + + /** + * Create a NamePath that is separated by dots. + */ + public static NamePath dotted(String... pieces) { + return parse("\\.", pieces); + } + + public static NamePath backslashed(String... pieces) { + return parse("\\\\", pieces); + } + + private static NamePath parse(String separatorRegex, String... pieces) { + List namePieces = new ArrayList<>(); + for (String piece : pieces) { + for (String subPiece : piece.split(separatorRegex)) { + namePieces.add(subPiece); + } + } + if (namePieces.size() == 0) { + throw new IllegalArgumentException("QualifiedName must not be zero length"); + } + return new NamePath(namePieces); + } + + private NamePath(List pathPieces) { + this.pathPieces = pathPieces; + } + + /** + * Create a new NamePath where the head (the last piece) is replaced with the + * given newHead. + */ + public NamePath withHead(String newHead) { + List newPathPieces = new ArrayList<>(); + newPathPieces.addAll(pathPieces); + newPathPieces.set(pathPieces.size() - 1, newHead); + return new NamePath(newPathPieces); + } + + /** + * Returns the head (last piece) of the NamePath. + */ + public String getHead() { + return pathPieces.get(pathPieces.size() - 1); + } + + /** + * Returns the namePath in dotted form. + */ + public String toDotted() { + return Joiner.on(".").join(pathPieces); + } + + /** + * Returns the namePath in backslashed form. + */ + public String toBackslashed() { + return Joiner.on("\\").join(pathPieces); + } +} diff --git a/src/main/java/com/google/api/codegen/util/TypeAlias.java b/src/main/java/com/google/api/codegen/util/TypeAlias.java new file mode 100644 index 0000000000..fbf3af4ce8 --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/TypeAlias.java @@ -0,0 +1,58 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util; + +import com.google.auto.value.AutoValue; + +/** + * TypeAlias represents an alias between a fully-qualified version of a name + * (the "fullName") and a short version of a name (the "nickname"). + */ +@AutoValue +public abstract class TypeAlias { + + /** + * Creates a TypeAlias where the fullName and nickname are the same. + */ + public static TypeAlias create(String name) { + return create(name, name); + } + + /** + * Standard constructor. + */ + public static TypeAlias create(String fullName, String nickname) { + return new AutoValue_TypeAlias(fullName, nickname); + } + + /** + * The full name of the alias. + */ + public abstract String getFullName(); + + /** + * The nickname of the alias. + */ + public abstract String getNickname(); + + /** + * Returns true if the alias needs to be imported to refer to it only + * through the nickname. This will be false if the full name and nickname + * are the same. + */ + public boolean needsImport() { + return !getFullName().equals(getNickname()); + } +} diff --git a/src/main/java/com/google/api/codegen/util/TypeName.java b/src/main/java/com/google/api/codegen/util/TypeName.java new file mode 100644 index 0000000000..552c7e2fdf --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/TypeName.java @@ -0,0 +1,106 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +/** + * Represents a simple or complex type and keeps track of the aliases for the contributing types. + */ +public class TypeName { + private final TypeAlias topLevelAlias; + private final String pattern; + private final List innerTypeNames; + + /** + * Constructs a TypeName where the full name and nickname are the same. + */ + public TypeName(String name) { + this(name, name); + } + + /** + * Standard constructor. + */ + public TypeName(String fullName, String nickname) { + this.topLevelAlias = TypeAlias.create(fullName, nickname); + this.pattern = null; + this.innerTypeNames = Arrays.asList(); + } + + /** + * Constructs a composite TypeName with a special string pattern to render the type, and a list + * of inner TypeName instances that parameterize the type. + * + * @param fullName full name + * @param nickname nickname + * @param pattern Use the pattern %s for self and %i for inner types, one for each inner type + * in the order that they are provided. If this is null, then the type name of + * the outer type is used, and inner type names are ignored. + * @param innerTypeNames + */ + public TypeName(String fullName, String nickname, String pattern, TypeName... innerTypeNames) { + this.topLevelAlias = TypeAlias.create(fullName, nickname); + this.pattern = pattern; + this.innerTypeNames = Arrays.asList(innerTypeNames); + } + + /** + * Renders the fully-qualified name of this type given its pattern. + */ + public String getFullName() { + if (pattern == null) { + return topLevelAlias.getFullName(); + } + String result = StringUtils.replaceOnce(pattern, "%s", topLevelAlias.getFullName()); + for (TypeName innerTypeName : innerTypeNames) { + result = StringUtils.replaceOnce(result, "%i", innerTypeName.getFullName()); + } + return result; + } + + /** + * Renders the short name of this type given its pattern. + */ + public String getNickname() { + if (pattern == null) { + return topLevelAlias.getNickname(); + } + String result = StringUtils.replaceOnce(pattern, "%s", topLevelAlias.getNickname()); + for (TypeName innerTypeName : innerTypeNames) { + result = StringUtils.replaceOnce(result, "%i", innerTypeName.getNickname()); + } + return result; + } + + /** + * Renders the short name of this type given its pattern, and adds any necessary nicknames + * to the given type table. + */ + public String getAndSaveNicknameIn(TypeTable typeTable) { + String topLevelNickname = typeTable.getAndSaveNicknameFor(topLevelAlias); + if (pattern == null) { + return topLevelNickname; + } + String result = StringUtils.replaceOnce(pattern, "%s", topLevelNickname); + for (TypeName innerTypeName : innerTypeNames) { + result = StringUtils.replaceOnce(result, "%i", innerTypeName.getAndSaveNicknameIn(typeTable)); + } + return result; + } +} diff --git a/src/main/java/com/google/api/codegen/java/JavaIterableSnippetSet.java b/src/main/java/com/google/api/codegen/util/TypeNameConverter.java similarity index 57% rename from src/main/java/com/google/api/codegen/java/JavaIterableSnippetSet.java rename to src/main/java/com/google/api/codegen/util/TypeNameConverter.java index e4c7e3cec3..9dd4dc6269 100644 --- a/src/main/java/com/google/api/codegen/java/JavaIterableSnippetSet.java +++ b/src/main/java/com/google/api/codegen/util/TypeNameConverter.java @@ -12,27 +12,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.api.codegen.java; - -import com.google.api.tools.framework.snippet.Doc; +package com.google.api.codegen.util; /** - * Entry points for a simple Java snippet set. Generation is a single phase. + * A TypeNameConverter maps Strings to TypeName instances. */ -interface JavaIterableSnippetSet { - +public interface TypeNameConverter { /** - * Generates the result filename for the generated document. + * Maps the given fullName to a TypeName. */ - Doc generateFilename(); + TypeName getTypeName(String fullName); /** - * Generates the contents of the document. + * Maps the given fullName to a NamePath. */ - Doc generateDocument(Iterable fragments); + NamePath getNamePath(String fullName); /** - * Generates a fragment of the doc from a service. + * Creates a TypeName for the container type and element type. */ - Doc generateFragment(T service); + TypeName getContainerTypeName(String containerFullName, String elementFullName); } diff --git a/src/main/java/com/google/api/codegen/util/TypeTable.java b/src/main/java/com/google/api/codegen/util/TypeTable.java new file mode 100644 index 0000000000..44117bb2de --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/TypeTable.java @@ -0,0 +1,61 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util; + +import java.util.List; + +/** + * A type table manages the imports for a set of fully-qualified type names. + */ +public interface TypeTable extends TypeNameConverter { + + @Override + TypeName getTypeName(String fullName); + + @Override + NamePath getNamePath(String fullName); + + @Override + TypeName getContainerTypeName(String containerFullName, String elementFullName); + + /** + * Return a new TypeTable with the same concrete type as this one. + */ + TypeTable cloneEmpty(); + + /** + * Computes the nickname for the given full name, adds the full name to the import set, + * and returns the nickname. + */ + String getAndSaveNicknameFor(String fullName); + + /** + * Computes the nickname for the given type, adds the full name to the import set, + * and returns the nickname. + */ + String getAndSaveNicknameFor(TypeName typeName); + + /** + * Determines if the nickname of the given alias can be used, and if so, then + * saves it in the import table and returns it; otherwise (e.g. if there would + * be a clash), returns the full name. + */ + String getAndSaveNicknameFor(TypeAlias alias); + + /** + * Returns the imports accumulated so far. + */ + List getImports(); +} diff --git a/src/main/java/com/google/api/codegen/util/TypedValue.java b/src/main/java/com/google/api/codegen/util/TypedValue.java new file mode 100644 index 0000000000..249f20b302 --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/TypedValue.java @@ -0,0 +1,51 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util; + +import com.google.auto.value.AutoValue; + +import org.apache.commons.lang3.StringUtils; + +/** + * Represents a value and its associated type. + */ +@AutoValue +public abstract class TypedValue { + + /** + * Create a TypedValue. The pattern "%s" in valuePattern is used by + * getValueAndSaveTypeNicknameIn to format the final value. + */ + public static TypedValue create(TypeName typeName, String valuePattern) { + return new AutoValue_TypedValue(typeName, valuePattern); + } + + public abstract TypeName getTypeName(); + + public abstract String getValuePattern(); + + /** + * Renders the value given the value pattern, and adds any necessary nicknames + * to the given type table. + */ + public String getValueAndSaveTypeNicknameIn(TypeTable typeTable) { + if (getValuePattern().contains("%s")) { + String nickname = typeTable.getAndSaveNicknameFor(getTypeName()); + return StringUtils.replaceOnce(getValuePattern(), "%s", nickname); + } else { + return getValuePattern(); + } + } +} diff --git a/src/main/java/com/google/api/codegen/util/java/JavaNameFormatter.java b/src/main/java/com/google/api/codegen/util/java/JavaNameFormatter.java new file mode 100644 index 0000000000..c478fbe9da --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/java/JavaNameFormatter.java @@ -0,0 +1,65 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util.java; + +import com.google.api.codegen.util.Name; +import com.google.api.codegen.util.NameFormatter; +import com.google.api.codegen.util.NamePath; + +/** + * The NameFormatter for Java. + */ +public class JavaNameFormatter implements NameFormatter { + + @Override + public String className(Name name) { + return name.toUpperCamel(); + } + + @Override + public String varName(Name name) { + return name.toLowerCamel(); + } + + @Override + public String varReference(Name name) { + return varName(name); + } + + @Override + public String methodName(Name name) { + return name.toLowerCamel(); + } + + @Override + public String staticFunctionName(Name name) { + return name.toLowerCamel(); + } + + @Override + public String inittedConstantName(Name name) { + return name.toUpperUnderscore(); + } + + @Override + public String keyName(Name name) { + return name.toLowerCamel(); + } + + @Override + public String qualifiedName(NamePath namePath) { + return namePath.toDotted(); + } +} diff --git a/src/main/java/com/google/api/codegen/util/java/JavaRenderingUtil.java b/src/main/java/com/google/api/codegen/util/java/JavaRenderingUtil.java new file mode 100644 index 0000000000..36a719be9c --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/java/JavaRenderingUtil.java @@ -0,0 +1,61 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util.java; + +import com.google.common.base.Splitter; +import com.google.common.escape.Escaper; +import com.google.common.escape.Escapers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Utility class for Java to process text in the templates. + */ +public class JavaRenderingUtil { + /** + * Escaper for formatting javadoc strings. + */ + private static final Escaper JAVADOC_ESCAPER = + Escapers.builder() + .addEscape('&', "&") + .addEscape('<', "<") + .addEscape('>', ">") + .addEscape('*', "*") + .build(); + + /** + * Splits given text into lines and returns an list of strings, each one representing a line. + * Performs escaping of certain html characters. + */ + public static List getDocLines(String text) { + // TODO: convert markdown to javadoc + // https://github.com/googleapis/toolkit/issues/331 + List result = new ArrayList<>(); + text = JAVADOC_ESCAPER.escape(text); + for (String line : Splitter.on(String.format("%n")).split(text)) { + result.add(line); + } + return result; + } + + public List getMultilineHeading(String heading) { + final char[] array = new char[heading.length()]; + Arrays.fill(array, '='); + String eqsString = new String(array); + return Arrays.asList(eqsString, heading, eqsString); + } +} diff --git a/src/main/java/com/google/api/codegen/util/java/JavaTypeTable.java b/src/main/java/com/google/api/codegen/util/java/JavaTypeTable.java new file mode 100644 index 0000000000..9d68902613 --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/java/JavaTypeTable.java @@ -0,0 +1,158 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util.java; + +import com.google.api.codegen.LanguageUtil; +import com.google.api.codegen.util.NamePath; +import com.google.api.codegen.util.TypeAlias; +import com.google.api.codegen.util.TypeName; +import com.google.api.codegen.util.TypeTable; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * The TypeTable for Java. + */ +public class JavaTypeTable implements TypeTable { + /** + * A bi-map from full names to short names indicating the import map. + */ + private final BiMap imports = HashBiMap.create(); + + /** + * A map from simple type name to a boolean, indicating whether its in java.lang or not. If a + * simple type name is not in the map, this information is unknown. + */ + private final Map implicitImports = Maps.newHashMap(); + + private static final String JAVA_LANG_TYPE_PREFIX = "java.lang."; + + /** + * A map from unboxed Java primitive type name to boxed counterpart. + */ + private static final ImmutableMap BOXED_TYPE_MAP = + ImmutableMap.builder() + .put("boolean", "Boolean") + .put("int", "Integer") + .put("long", "Long") + .put("float", "Float") + .put("double", "Double") + .build(); + + @Override + public TypeTable cloneEmpty() { + return new JavaTypeTable(); + } + + public TypeName getTypeName(String fullName) { + int lastDotIndex = fullName.lastIndexOf('.'); + if (lastDotIndex < 0) { + return new TypeName(fullName, fullName); + } + String shortTypeName = fullName.substring(lastDotIndex + 1); + return new TypeName(fullName, shortTypeName); + } + + @Override + public NamePath getNamePath(String fullName) { + return NamePath.dotted(fullName); + } + + @Override + public TypeName getContainerTypeName(String containerFullName, String elementFullName) { + TypeName containerTypeName = getTypeName(containerFullName); + TypeName elementTypeName = getTypeName(elementFullName); + return new TypeName( + containerTypeName.getFullName(), + containerTypeName.getNickname(), + "%s<%i>", + elementTypeName); + } + + public String getAndSaveNicknameFor(String fullName) { + return getAndSaveNicknameFor(getTypeName(fullName)); + } + + public String getAndSaveNicknameFor(TypeName typeName) { + return typeName.getAndSaveNicknameIn(this); + } + + @Override + public String getAndSaveNicknameFor(TypeAlias alias) { + if (!alias.needsImport()) { + return alias.getNickname(); + } + // Derive a short name if possible + if (imports.containsKey(alias.getFullName())) { + // Short name already there. + return imports.get(alias.getFullName()); + } + if (imports.containsValue(alias.getNickname()) + || !alias.getFullName().startsWith(JAVA_LANG_TYPE_PREFIX) + && isImplicitImport(alias.getNickname())) { + // Short name clashes, use long name. + return alias.getFullName(); + } + imports.put(alias.getFullName(), alias.getNickname()); + return alias.getNickname(); + } + + /** + * Returns the Java representation of a basic type in boxed form. + */ + public static String getBoxedTypeName(String primitiveTypeName) { + return LanguageUtil.getRename(primitiveTypeName, BOXED_TYPE_MAP); + } + + public List getImports() { + // Clean up the imports. + List cleanedImports = new ArrayList<>(); + for (String imported : imports.keySet()) { + if (imported.startsWith(JAVA_LANG_TYPE_PREFIX)) { + // Imported type is in java.lang or in package, can be ignored. + continue; + } + cleanedImports.add(imported); + } + Collections.sort(cleanedImports); + return cleanedImports; + } + + /** + * Checks whether the simple type name is implicitly imported from java.lang. + */ + private boolean isImplicitImport(String name) { + Boolean yes = implicitImports.get(name); + if (yes != null) { + return yes; + } + // Use reflection to determine whether the name exists in java.lang. + try { + Class.forName("java.lang." + name); + yes = true; + } catch (Exception e) { + yes = false; + } + implicitImports.put(name, yes); + return yes; + } +} diff --git a/src/main/java/com/google/api/codegen/util/php/PhpNameFormatter.java b/src/main/java/com/google/api/codegen/util/php/PhpNameFormatter.java new file mode 100644 index 0000000000..b4de7d029b --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/php/PhpNameFormatter.java @@ -0,0 +1,65 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util.php; + +import com.google.api.codegen.util.Name; +import com.google.api.codegen.util.NameFormatter; +import com.google.api.codegen.util.NamePath; + +/** + * The NameFormatter for PHP. + */ +public class PhpNameFormatter implements NameFormatter { + + @Override + public String className(Name name) { + return name.toUpperCamel(); + } + + @Override + public String varName(Name name) { + return name.toLowerCamel(); + } + + @Override + public String varReference(Name name) { + return "$" + varName(name); + } + + @Override + public String methodName(Name name) { + return name.toLowerCamel(); + } + + @Override + public String staticFunctionName(Name name) { + return name.toLowerCamel(); + } + + @Override + public String inittedConstantName(Name name) { + return name.toLowerCamel(); + } + + @Override + public String keyName(Name name) { + return name.toLowerCamel(); + } + + @Override + public String qualifiedName(NamePath namePath) { + return namePath.toBackslashed(); + } +} diff --git a/src/main/java/com/google/api/codegen/util/php/PhpTypeTable.java b/src/main/java/com/google/api/codegen/util/php/PhpTypeTable.java new file mode 100644 index 0000000000..896b834233 --- /dev/null +++ b/src/main/java/com/google/api/codegen/util/php/PhpTypeTable.java @@ -0,0 +1,188 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.util.php; + +import com.google.api.codegen.util.NamePath; +import com.google.api.codegen.util.TypeAlias; +import com.google.api.codegen.util.TypeName; +import com.google.api.codegen.util.TypeTable; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.ImmutableSet; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * The TypeTable for PHP. + */ +public class PhpTypeTable implements TypeTable { + /** + * A bi-map from full names to short names indicating the import map. + */ + private final BiMap imports = HashBiMap.create(); + + @Override + public TypeTable cloneEmpty() { + return new PhpTypeTable(); + } + + @Override + public TypeName getTypeName(String fullName) { + int lastBackslashIndex = fullName.lastIndexOf('\\'); + if (lastBackslashIndex < 0) { + throw new IllegalArgumentException("expected fully qualified name"); + } + String nickname = fullName.substring(lastBackslashIndex + 1); + return new TypeName(fullName, nickname); + } + + @Override + public NamePath getNamePath(String fullName) { + return NamePath.backslashed(fullName); + } + + @Override + public TypeName getContainerTypeName(String containerFullName, String elementFullName) { + return getTypeName(containerFullName); + } + + @Override + public String getAndSaveNicknameFor(String fullName) { + return getAndSaveNicknameFor(getTypeName(fullName)); + } + + @Override + public String getAndSaveNicknameFor(TypeName typeName) { + return typeName.getAndSaveNicknameIn(this); + } + + @Override + public String getAndSaveNicknameFor(TypeAlias alias) { + if (!alias.needsImport()) { + return alias.getNickname(); + } + // Derive a short name if possible + if (imports.containsKey(alias.getFullName())) { + // Short name already there. + return imports.get(alias.getFullName()); + } + if (imports.containsValue(alias.getNickname())) { + // Short name clashes, use long name. + return alias.getFullName(); + } + imports.put(alias.getFullName(), alias.getNickname()); + return alias.getNickname(); + } + + @Override + public List getImports() { + // Clean up the imports. + List cleanedImports = new ArrayList<>(); + for (String imported : imports.keySet()) { + cleanedImports.add(imported); + } + Collections.sort(cleanedImports); + return cleanedImports; + } + + public boolean hasImports() { + return !getImports().isEmpty(); + } + + /** + * A set of PHP keywords and built-ins. keywords: http://php.net/manual/en/reserved.keywords.php + */ + private static final ImmutableSet KEYWORD_BUILT_IN_SET = + ImmutableSet.builder() + .add( + "__halt_compiler", + "abstract", + "and", + "array", + "as", + "break", + "callable", + "case", + "catch", + "class", + "clone", + "const", + "continue", + "declare", + "default", + "die", + "do", + "echo", + "else", + "elseif", + "empty", + "enddeclare", + "endfor", + "endforeach", + "endif", + "endswitch", + "endwhile", + "eval", + "exit", + "extends", + "final", + "finally", + "for", + "foreach", + "function", + "global", + "goto", + "if", + "implements", + "include", + "include_once", + "instanceof", + "insteadof", + "interface", + "isset", + "list", + "namespace", + "new", + "or", + "print", + "private", + "protected", + "public", + "require", + "require_once", + "return", + "static", + "switch", + "throw", + "trait", + "try", + "unset", + "use", + "var", + "while", + "xor", + "yield", + "__CLASS__", + "__DIR__", + "__FILE__", + "__FUNCTION__", + "__LINE__", + "__METHOD__", + "__NAMESPACE__", + "__TRAIT__") + .build(); +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ApiCallSettingsView.java b/src/main/java/com/google/api/codegen/viewmodel/ApiCallSettingsView.java new file mode 100644 index 0000000000..258215cabe --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ApiCallSettingsView.java @@ -0,0 +1,88 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import javax.annotation.Nullable; + +@AutoValue +public abstract class ApiCallSettingsView { + public abstract ApiCallableType type(); + + public abstract String methodName(); + + public abstract String requestTypeName(); + + public abstract String responseTypeName(); + + public abstract String resourceTypeName(); + + public abstract String memberName(); + + public abstract String fnGetterName(); + + public abstract String grpcTypeName(); + + public abstract String grpcMethodConstant(); + + public abstract String pageStreamingDescriptorName(); + + public abstract String bundlingDescriptorName(); + + public abstract String retryCodesName(); + + public abstract String retryParamsName(); + + @Nullable + public abstract BundlingConfigView bundlingConfig(); + + public static Builder newBuilder() { + return new AutoValue_ApiCallSettingsView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder type(ApiCallableType type); + + public abstract Builder methodName(String apiMethodName); + + public abstract Builder requestTypeName(String val); + + public abstract Builder responseTypeName(String val); + + public abstract Builder resourceTypeName(String val); + + public abstract Builder memberName(String val); + + public abstract Builder fnGetterName(String val); + + public abstract Builder grpcTypeName(String val); + + public abstract Builder grpcMethodConstant(String val); + + public abstract Builder pageStreamingDescriptorName(String val); + + public abstract Builder bundlingDescriptorName(String val); + + public abstract Builder bundlingConfig(BundlingConfigView val); + + public abstract Builder retryCodesName(String val); + + public abstract Builder retryParamsName(String val); + + public abstract ApiCallSettingsView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ApiCallableType.java b/src/main/java/com/google/api/codegen/viewmodel/ApiCallableType.java new file mode 100644 index 0000000000..0126026268 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ApiCallableType.java @@ -0,0 +1,21 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +public enum ApiCallableType { + SimpleApiCallable, + PagedApiCallable, + BundlingApiCallable +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ApiCallableView.java b/src/main/java/com/google/api/codegen/viewmodel/ApiCallableView.java new file mode 100644 index 0000000000..d28ac97b69 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ApiCallableView.java @@ -0,0 +1,49 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class ApiCallableView { + public abstract ApiCallableType type(); + + public abstract String requestTypeName(); + + public abstract String responseTypeName(); + + public abstract String name(); + + public abstract String settingsFunctionName(); + + public static Builder newBuilder() { + return new AutoValue_ApiCallableView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder type(ApiCallableType type); + + public abstract Builder requestTypeName(String name); + + public abstract Builder responseTypeName(String name); + + public abstract Builder name(String name); + + public abstract Builder settingsFunctionName(String name); + + public abstract ApiCallableView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ApiMethodDocView.java b/src/main/java/com/google/api/codegen/viewmodel/ApiMethodDocView.java new file mode 100644 index 0000000000..47adef5367 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ApiMethodDocView.java @@ -0,0 +1,51 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +import javax.annotation.Nullable; + +@AutoValue +public abstract class ApiMethodDocView { + + public abstract Iterable mainDocLines(); + + public abstract List paramDocs(); + + public abstract List throwsDocLines(); + + @Nullable + public abstract String returnTypeName(); + + public static Builder newBuilder() { + return new AutoValue_ApiMethodDocView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder mainDocLines(Iterable lines); + + public abstract Builder paramDocs(List docs); + + public abstract Builder throwsDocLines(List lines); + + public abstract Builder returnTypeName(String name); + + public abstract ApiMethodDocView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ApiMethodType.java b/src/main/java/com/google/api/codegen/viewmodel/ApiMethodType.java new file mode 100644 index 0000000000..4e2e6f741c --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ApiMethodType.java @@ -0,0 +1,29 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +public enum ApiMethodType { + // Java + PagedFlattenedMethod, + PagedRequestObjectMethod, + PagedCallableMethod, + UnpagedListCallableMethod, + FlattenedMethod, + RequestObjectMethod, + CallableMethod, + // PHP + OptionalArrayMethod, + PagedOptionalArrayMethod +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ApiMethodView.java b/src/main/java/com/google/api/codegen/viewmodel/ApiMethodView.java new file mode 100644 index 0000000000..30ffadba5c --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ApiMethodView.java @@ -0,0 +1,17 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +public interface ApiMethodView {} diff --git a/src/main/java/com/google/api/codegen/viewmodel/BundlingConfigView.java b/src/main/java/com/google/api/codegen/viewmodel/BundlingConfigView.java new file mode 100644 index 0000000000..0221e0d5df --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/BundlingConfigView.java @@ -0,0 +1,49 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class BundlingConfigView { + public abstract int elementCountThreshold(); + + public abstract long requestByteThreshold(); + + public abstract int elementCountLimit(); + + public abstract long requestByteLimit(); + + public abstract long delayThresholdMillis(); + + public static Builder newBuilder() { + return new AutoValue_BundlingConfigView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder elementCountThreshold(int val); + + public abstract Builder requestByteThreshold(long val); + + public abstract Builder elementCountLimit(int val); + + public abstract Builder requestByteLimit(long val); + + public abstract Builder delayThresholdMillis(long val); + + public abstract BundlingConfigView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/BundlingDescriptorClassView.java b/src/main/java/com/google/api/codegen/viewmodel/BundlingDescriptorClassView.java new file mode 100644 index 0000000000..e7fe49d66f --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/BundlingDescriptorClassView.java @@ -0,0 +1,82 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class BundlingDescriptorClassView { + + public abstract String name(); + + public abstract String requestTypeName(); + + public abstract String responseTypeName(); + + public abstract String bundledFieldTypeName(); + + public abstract String subresponseTypeName(); + + public abstract List partitionKeys(); + + public abstract List discriminatorFieldCopies(); + + public abstract String fnGetBundledField(); + + public abstract String fnSetBundledField(); + + public abstract String fnGetBundledFieldCount(); + + public abstract String fnGetSubresponseByIndex(); + + public abstract String fnSetSubresponse(); + + public static Builder newBuilder() { + return new AutoValue_BundlingDescriptorClassView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + + public abstract Builder name(String val); + + public abstract Builder requestTypeName(String val); + + public abstract Builder responseTypeName(String val); + + public abstract Builder bundledFieldTypeName(String val); + + public abstract Builder subresponseTypeName(String val); + + public abstract Builder partitionKeys(List val); + + public abstract Builder discriminatorFieldCopies( + List generateDiscriminatorFieldCopies); + + public abstract Builder fnGetBundledField(String val); + + public abstract Builder fnSetBundledField(String val); + + public abstract Builder fnGetBundledFieldCount(String val); + + public abstract Builder fnGetSubresponseByIndex(String val); + + public abstract Builder fnSetSubresponse(String val); + + public abstract BundlingDescriptorClassView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/BundlingPartitionKeyView.java b/src/main/java/com/google/api/codegen/viewmodel/BundlingPartitionKeyView.java new file mode 100644 index 0000000000..2f1ee8a648 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/BundlingPartitionKeyView.java @@ -0,0 +1,40 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.codegen.viewmodel.BundlingDescriptorClassView.Builder; +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class BundlingPartitionKeyView { + + public abstract String separatorLiteral(); + + public abstract String fnGetCallName(); + + public static Builder newBuilder() { + return new AutoValue_BundlingPartitionKeyView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + + public abstract Builder separatorLiteral(String val); + + public abstract Builder fnGetCallName(String val); + + public abstract BundlingPartitionKeyView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/CallableMethodDetailView.java b/src/main/java/com/google/api/codegen/viewmodel/CallableMethodDetailView.java new file mode 100644 index 0000000000..b98223e3a8 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/CallableMethodDetailView.java @@ -0,0 +1,37 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class CallableMethodDetailView { + public abstract String callableName(); + + public abstract String genericAwareResponseType(); + + public static Builder newBuilder() { + return new AutoValue_CallableMethodDetailView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder callableName(String name); + + public abstract Builder genericAwareResponseType(String name); + + public abstract CallableMethodDetailView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/DynamicDefaultableParamView.java b/src/main/java/com/google/api/codegen/viewmodel/DynamicDefaultableParamView.java new file mode 100644 index 0000000000..a9a84d75b4 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/DynamicDefaultableParamView.java @@ -0,0 +1,37 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class DynamicDefaultableParamView { + public abstract String name(); + + public abstract String defaultValue(); + + public static Builder newBuilder() { + return new AutoValue_DynamicDefaultableParamView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder name(String name); + + public abstract Builder defaultValue(String value); + + public abstract DynamicDefaultableParamView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/DynamicXApiView.java b/src/main/java/com/google/api/codegen/viewmodel/DynamicXApiView.java new file mode 100644 index 0000000000..b6c96b8db2 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/DynamicXApiView.java @@ -0,0 +1,121 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.codegen.SnippetSetRunner; +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class DynamicXApiView implements ViewModel { + public abstract String templateFileName(); + + public abstract String packageName(); + + public abstract String protoFilename(); + + public abstract ServiceDocView doc(); + + public abstract String name(); + + public abstract String serviceAddress(); + + public abstract Integer servicePort(); + + public abstract String serviceTitle(); + + public abstract Iterable authScopes(); + + public abstract List pathTemplates(); + + public abstract List formatResourceFunctions(); + + public abstract List parseResourceFunctions(); + + public abstract List pathTemplateGetterFunctions(); + + public abstract List pageStreamingDescriptors(); + + public abstract List methodKeys(); + + public abstract String clientConfigPath(); + + public abstract String interfaceKey(); + + public abstract String grpcClientTypeName(); + + public abstract List imports(); + + public abstract String outputPath(); + + public abstract List apiMethods(); + + @Override + public String resourceRoot() { + return SnippetSetRunner.SNIPPET_RESOURCE_ROOT; + } + + public static Builder newBuilder() { + return new AutoValue_DynamicXApiView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder templateFileName(String val); + + public abstract Builder packageName(String val); + + public abstract Builder protoFilename(String simpleName); + + public abstract Builder doc(ServiceDocView doc); + + public abstract Builder name(String val); + + public abstract Builder serviceAddress(String val); + + public abstract Builder servicePort(Integer val); + + public abstract Builder serviceTitle(String val); + + public abstract Builder authScopes(Iterable val); + + public abstract Builder pathTemplates(List val); + + public abstract Builder formatResourceFunctions(List val); + + public abstract Builder parseResourceFunctions(List val); + + public abstract Builder pathTemplateGetterFunctions(List val); + + public abstract Builder pageStreamingDescriptors(List val); + + public abstract Builder methodKeys(List val); + + public abstract Builder clientConfigPath(String val); + + public abstract Builder interfaceKey(String val); + + public abstract Builder grpcClientTypeName(String val); + + public abstract Builder imports(List val); + + public abstract Builder outputPath(String val); + + public abstract Builder apiMethods(List val); + + public abstract DynamicXApiView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/FieldCopyView.java b/src/main/java/com/google/api/codegen/viewmodel/FieldCopyView.java new file mode 100644 index 0000000000..a636db4a5f --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/FieldCopyView.java @@ -0,0 +1,38 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class FieldCopyView { + + public abstract String fnSetFunctionCallName(); + + public abstract String fnGetFunctionCallName(); + + public static Builder newBuilder() { + return new AutoValue_FieldCopyView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder fnSetFunctionCallName(String val); + + public abstract Builder fnGetFunctionCallName(String val); + + public abstract FieldCopyView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/FieldSettingView.java b/src/main/java/com/google/api/codegen/viewmodel/FieldSettingView.java new file mode 100644 index 0000000000..af44754685 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/FieldSettingView.java @@ -0,0 +1,38 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class FieldSettingView { + + public abstract String fnSetFunctionCallName(); + + public abstract String identifier(); + + public static Builder newBuilder() { + return new AutoValue_FieldSettingView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder fnSetFunctionCallName(String val); + + public abstract Builder identifier(String val); + + public abstract FieldSettingView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/FormatResourceFunctionView.java b/src/main/java/com/google/api/codegen/viewmodel/FormatResourceFunctionView.java new file mode 100644 index 0000000000..c8d966389d --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/FormatResourceFunctionView.java @@ -0,0 +1,51 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class FormatResourceFunctionView { + public abstract String entityName(); + + public abstract String name(); + + public abstract List resourceIdParams(); + + public abstract String pathTemplateName(); + + public abstract String pathTemplateGetterName(); + + public static Builder newBuilder() { + return new AutoValue_FormatResourceFunctionView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder entityName(String val); + + public abstract Builder name(String val); + + public abstract Builder resourceIdParams(List val); + + public abstract Builder pathTemplateName(String val); + + public abstract Builder pathTemplateGetterName(String val); + + public abstract FormatResourceFunctionView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/FormattedInitValueView.java b/src/main/java/com/google/api/codegen/viewmodel/FormattedInitValueView.java new file mode 100644 index 0000000000..48b96ed3ce --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/FormattedInitValueView.java @@ -0,0 +1,47 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class FormattedInitValueView implements InitValueView { + public abstract String apiWrapperName(); + + public abstract String formatFunctionName(); + + public abstract List formatArgs(); + + public String type() { + return FormattedInitValueView.class.getSimpleName(); + } + + public static Builder newBuilder() { + return new AutoValue_FormattedInitValueView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder apiWrapperName(String val); + + public abstract Builder formatFunctionName(String val); + + public abstract Builder formatArgs(List val); + + public abstract FormattedInitValueView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/InitCodeLineView.java b/src/main/java/com/google/api/codegen/viewmodel/InitCodeLineView.java new file mode 100644 index 0000000000..5f2a15829f --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/InitCodeLineView.java @@ -0,0 +1,17 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +public interface InitCodeLineView {} diff --git a/src/main/java/com/google/api/codegen/viewmodel/InitCodeView.java b/src/main/java/com/google/api/codegen/viewmodel/InitCodeView.java new file mode 100644 index 0000000000..4df98bc6c9 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/InitCodeView.java @@ -0,0 +1,39 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class InitCodeView { + public abstract List lines(); + + public abstract List fieldSettings(); + + public static Builder newBuilder() { + return new AutoValue_InitCodeView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder lines(List val); + + public abstract Builder fieldSettings(List val); + + public abstract InitCodeView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/InitValueView.java b/src/main/java/com/google/api/codegen/viewmodel/InitValueView.java new file mode 100644 index 0000000000..8410b22b0d --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/InitValueView.java @@ -0,0 +1,17 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +public interface InitValueView {} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ListInitCodeLineView.java b/src/main/java/com/google/api/codegen/viewmodel/ListInitCodeLineView.java new file mode 100644 index 0000000000..5e48d2a13e --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ListInitCodeLineView.java @@ -0,0 +1,49 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.codegen.metacode.InitCodeLineType; +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class ListInitCodeLineView implements InitCodeLineView { + + public abstract InitCodeLineType lineType(); + + public abstract String elementTypeName(); + + public abstract String identifier(); + + public abstract List elementIdentifiers(); + + public static Builder newBuilder() { + return new AutoValue_ListInitCodeLineView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder lineType(InitCodeLineType val); + + public abstract Builder elementTypeName(String val); + + public abstract Builder identifier(String val); + + public abstract Builder elementIdentifiers(List val); + + public abstract ListInitCodeLineView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ListMethodDetailView.java b/src/main/java/com/google/api/codegen/viewmodel/ListMethodDetailView.java new file mode 100644 index 0000000000..f0379366ed --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ListMethodDetailView.java @@ -0,0 +1,33 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class ListMethodDetailView { + public abstract String resourceTypeName(); + + public static Builder newBuilder() { + return new AutoValue_ListMethodDetailView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder resourceTypeName(String name); + + public abstract ListMethodDetailView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/MapEntryView.java b/src/main/java/com/google/api/codegen/viewmodel/MapEntryView.java new file mode 100644 index 0000000000..0558bf8f8f --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/MapEntryView.java @@ -0,0 +1,37 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class MapEntryView { + public abstract String key(); + + public abstract String value(); + + public static Builder newBuilder() { + return new AutoValue_MapEntryView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder key(String key); + + public abstract Builder value(String value); + + public abstract MapEntryView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/MapInitCodeLineView.java b/src/main/java/com/google/api/codegen/viewmodel/MapInitCodeLineView.java new file mode 100644 index 0000000000..df81aa7f53 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/MapInitCodeLineView.java @@ -0,0 +1,52 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.codegen.metacode.InitCodeLineType; +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class MapInitCodeLineView implements InitCodeLineView { + public abstract InitCodeLineType lineType(); + + public abstract String keyTypeName(); + + public abstract String valueTypeName(); + + public abstract String identifier(); + + public abstract List initEntries(); + + public static Builder newBuilder() { + return new AutoValue_MapInitCodeLineView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder lineType(InitCodeLineType val); + + public abstract Builder keyTypeName(String val); + + public abstract Builder valueTypeName(String val); + + public abstract Builder identifier(String val); + + public abstract Builder initEntries(List val); + + public abstract MapInitCodeLineView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/MapParamDocView.java b/src/main/java/com/google/api/codegen/viewmodel/MapParamDocView.java new file mode 100644 index 0000000000..7858c61456 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/MapParamDocView.java @@ -0,0 +1,55 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class MapParamDocView implements ParamDocView { + public abstract String paramName(); + + public abstract String typeName(); + + public abstract String firstLine(); + + public abstract List remainingLines(); + + public abstract List arrayKeyDocs(); + + public String type() { + return MapParamDocView.class.getSimpleName(); + } + + public static Builder newBuilder() { + return new AutoValue_MapParamDocView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder paramName(String val); + + public abstract Builder typeName(String val); + + public abstract Builder firstLine(String val); + + public abstract Builder remainingLines(List val); + + public abstract Builder arrayKeyDocs(List val); + + public abstract MapParamDocView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/OptionalArrayMethodView.java b/src/main/java/com/google/api/codegen/viewmodel/OptionalArrayMethodView.java new file mode 100644 index 0000000000..32ac7a5588 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/OptionalArrayMethodView.java @@ -0,0 +1,84 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class OptionalArrayMethodView implements ApiMethodView { + + public abstract ApiMethodType type(); + + public abstract String apiClassName(); + + public abstract String apiVariableName(); + + public abstract InitCodeView initCode(); + + public abstract ApiMethodDocView doc(); + + public abstract String name(); + + public abstract String requestTypeName(); + + public abstract String key(); + + public abstract String grpcMethodName(); + + public abstract List methodParams(); + + public abstract List requiredRequestObjectParams(); + + public abstract List optionalRequestObjectParams(); + + public abstract boolean hasReturnValue(); + + public static Builder newBuilder() { + return new AutoValue_OptionalArrayMethodView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder type(ApiMethodType val); + + public abstract Builder apiClassName(String val); + + public abstract Builder apiVariableName(String val); + + public abstract Builder initCode(InitCodeView val); + + public abstract Builder doc(ApiMethodDocView val); + + public abstract Builder name(String val); + + public abstract Builder requestTypeName(String val); + + public abstract Builder key(String val); + + public abstract Builder grpcMethodName(String val); + + public abstract Builder methodParams(List val); + + public abstract Builder requiredRequestObjectParams(List val); + + public abstract Builder optionalRequestObjectParams(List val); + + public abstract Builder hasReturnValue(boolean val); + + public abstract OptionalArrayMethodView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/PackageInfoView.java b/src/main/java/com/google/api/codegen/viewmodel/PackageInfoView.java new file mode 100644 index 0000000000..59d2fefcda --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/PackageInfoView.java @@ -0,0 +1,60 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.codegen.SnippetSetRunner; +import com.google.api.codegen.viewmodel.StaticXApiView.Builder; +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class PackageInfoView implements ViewModel { + @Override + public abstract String templateFileName(); + + @Override + public abstract String outputPath(); + + public abstract String serviceTitle(); + + public abstract List serviceDocs(); + + public abstract String packageName(); + + @Override + public String resourceRoot() { + return SnippetSetRunner.SNIPPET_RESOURCE_ROOT; + } + + public static Builder newBuilder() { + return new AutoValue_PackageInfoView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder templateFileName(String val); + + public abstract Builder outputPath(String val); + + public abstract Builder serviceTitle(String val); + + public abstract Builder serviceDocs(List val); + + public abstract Builder packageName(String val); + + public abstract PackageInfoView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/PageStreamingDescriptorClassView.java b/src/main/java/com/google/api/codegen/viewmodel/PageStreamingDescriptorClassView.java new file mode 100644 index 0000000000..7d3c4e2ebf --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/PageStreamingDescriptorClassView.java @@ -0,0 +1,66 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class PageStreamingDescriptorClassView { + public abstract String name(); + + public abstract String requestTypeName(); + + public abstract String responseTypeName(); + + public abstract String resourceTypeName(); + + public abstract String tokenTypeName(); + + public abstract String defaultTokenValue(); + + public abstract String fnSetRequestToken(); + + public abstract String fnGetResponseToken(); + + public abstract String fnGetResourcesField(); + + public static Builder newBuilder() { + return new AutoValue_PageStreamingDescriptorClassView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + + public abstract Builder name(String val); + + public abstract Builder requestTypeName(String val); + + public abstract Builder responseTypeName(String val); + + public abstract Builder resourceTypeName(String val); + + public abstract Builder tokenTypeName(String val); + + public abstract Builder defaultTokenValue(String val); + + public abstract Builder fnSetRequestToken(String val); + + public abstract Builder fnGetResponseToken(String val); + + public abstract Builder fnGetResourcesField(String val); + + public abstract PageStreamingDescriptorClassView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/PageStreamingDescriptorView.java b/src/main/java/com/google/api/codegen/viewmodel/PageStreamingDescriptorView.java new file mode 100644 index 0000000000..90cb13d634 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/PageStreamingDescriptorView.java @@ -0,0 +1,49 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class PageStreamingDescriptorView { + public abstract String varName(); + + public abstract String requestTokenFieldName(); + + public abstract String responseTokenFieldName(); + + public abstract String resourcesFieldName(); + + public abstract String methodName(); + + public static Builder newBuilder() { + return new AutoValue_PageStreamingDescriptorView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder varName(String val); + + public abstract Builder requestTokenFieldName(String val); + + public abstract Builder responseTokenFieldName(String val); + + public abstract Builder resourcesFieldName(String val); + + public abstract Builder methodName(String val); + + public abstract PageStreamingDescriptorView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ParamDocView.java b/src/main/java/com/google/api/codegen/viewmodel/ParamDocView.java new file mode 100644 index 0000000000..068c3d4efb --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ParamDocView.java @@ -0,0 +1,17 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +public interface ParamDocView {} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ParseResourceFunctionView.java b/src/main/java/com/google/api/codegen/viewmodel/ParseResourceFunctionView.java new file mode 100644 index 0000000000..3d60b53678 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ParseResourceFunctionView.java @@ -0,0 +1,53 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class ParseResourceFunctionView { + public abstract String entityName(); + + public abstract String name(); + + public abstract String pathTemplateName(); + + public abstract String pathTemplateGetterName(); + + public abstract String entityNameParamName(); + + public abstract String outputResourceId(); + + public static Builder newBuilder() { + return new AutoValue_ParseResourceFunctionView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder entityName(String val); + + public abstract Builder name(String val); + + public abstract Builder pathTemplateName(String val); + + public abstract Builder pathTemplateGetterName(String val); + + public abstract Builder entityNameParamName(String val); + + public abstract Builder outputResourceId(String val); + + public abstract ParseResourceFunctionView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/PathTemplateCheckView.java b/src/main/java/com/google/api/codegen/viewmodel/PathTemplateCheckView.java new file mode 100644 index 0000000000..a71a6d3029 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/PathTemplateCheckView.java @@ -0,0 +1,38 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class PathTemplateCheckView { + + public abstract String pathTemplateName(); + + public abstract String paramName(); + + public static Builder newBuilder() { + return new AutoValue_PathTemplateCheckView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder pathTemplateName(String val); + + public abstract Builder paramName(String val); + + public abstract PathTemplateCheckView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/PathTemplateGetterFunctionView.java b/src/main/java/com/google/api/codegen/viewmodel/PathTemplateGetterFunctionView.java new file mode 100644 index 0000000000..8806fb2dca --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/PathTemplateGetterFunctionView.java @@ -0,0 +1,42 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class PathTemplateGetterFunctionView { + + public abstract String name(); + + public abstract String pathTemplateName(); + + public abstract String pattern(); + + public static Builder newBuilder() { + return new AutoValue_PathTemplateGetterFunctionView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder name(String val); + + public abstract Builder pathTemplateName(String val); + + public abstract Builder pattern(String val); + + public abstract PathTemplateGetterFunctionView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/PathTemplateView.java b/src/main/java/com/google/api/codegen/viewmodel/PathTemplateView.java new file mode 100644 index 0000000000..25616f0a61 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/PathTemplateView.java @@ -0,0 +1,37 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class PathTemplateView { + public abstract String name(); + + public abstract String pattern(); + + public static Builder newBuilder() { + return new AutoValue_PathTemplateView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder name(String val); + + public abstract Builder pattern(String val); + + public abstract PathTemplateView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/RequestObjectMethodDetailView.java b/src/main/java/com/google/api/codegen/viewmodel/RequestObjectMethodDetailView.java new file mode 100644 index 0000000000..3f1a896b53 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/RequestObjectMethodDetailView.java @@ -0,0 +1,37 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class RequestObjectMethodDetailView { + public abstract String accessModifier(); + + public abstract String callableMethodName(); + + public static Builder newBuilder() { + return new AutoValue_RequestObjectMethodDetailView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder accessModifier(String modifier); + + public abstract Builder callableMethodName(String name); + + public abstract RequestObjectMethodDetailView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/RequestObjectParamView.java b/src/main/java/com/google/api/codegen/viewmodel/RequestObjectParamView.java new file mode 100644 index 0000000000..c1a79ede69 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/RequestObjectParamView.java @@ -0,0 +1,53 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class RequestObjectParamView { + public abstract String name(); + + public abstract String elementTypeName(); + + public abstract String typeName(); + + public abstract String setCallName(); + + public abstract boolean isMap(); + + public abstract boolean isArray(); + + public static Builder newBuilder() { + return new AutoValue_RequestObjectParamView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder name(String val); + + public abstract Builder elementTypeName(String val); + + public abstract Builder typeName(String val); + + public abstract Builder setCallName(String val); + + public abstract Builder isMap(boolean val); + + public abstract Builder isArray(boolean val); + + public abstract RequestObjectParamView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ResourceIdParamView.java b/src/main/java/com/google/api/codegen/viewmodel/ResourceIdParamView.java new file mode 100644 index 0000000000..0c8ae0d346 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ResourceIdParamView.java @@ -0,0 +1,37 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class ResourceIdParamView { + public abstract String name(); + + public abstract String templateKey(); + + public static Builder newBuilder() { + return new AutoValue_ResourceIdParamView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder name(String val); + + public abstract Builder templateKey(String val); + + public abstract ResourceIdParamView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/RetryCodesDefinitionView.java b/src/main/java/com/google/api/codegen/viewmodel/RetryCodesDefinitionView.java new file mode 100644 index 0000000000..bfc9dbea30 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/RetryCodesDefinitionView.java @@ -0,0 +1,40 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableSet; + +import io.grpc.Status.Code; + +@AutoValue +public abstract class RetryCodesDefinitionView { + public abstract String key(); + + public abstract ImmutableSet codes(); + + public static Builder newBuilder() { + return new AutoValue_RetryCodesDefinitionView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder key(String val); + + public abstract Builder codes(ImmutableSet val); + + public abstract RetryCodesDefinitionView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/RetryParamsDefinitionView.java b/src/main/java/com/google/api/codegen/viewmodel/RetryParamsDefinitionView.java new file mode 100644 index 0000000000..93fd57b15a --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/RetryParamsDefinitionView.java @@ -0,0 +1,67 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.gax.core.RetrySettings.Builder; +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableSet; + +import io.grpc.Status.Code; + +import org.joda.time.Duration; + +@AutoValue +public abstract class RetryParamsDefinitionView { + public abstract String key(); + + public abstract Duration totalTimeout(); + + public abstract Duration initialRetryDelay(); + + public abstract double retryDelayMultiplier(); + + public abstract Duration maxRetryDelay(); + + public abstract Duration initialRpcTimeout(); + + public abstract double rpcTimeoutMultiplier(); + + public abstract Duration maxRpcTimeout(); + + public static Builder newBuilder() { + return new AutoValue_RetryParamsDefinitionView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder key(String val); + + public abstract Builder initialRetryDelay(Duration initialDelay); + + public abstract Builder retryDelayMultiplier(double multiplier); + + public abstract Builder maxRetryDelay(Duration maxDelay); + + public abstract Builder initialRpcTimeout(Duration initialTimeout); + + public abstract Builder rpcTimeoutMultiplier(double multiplier); + + public abstract Builder maxRpcTimeout(Duration maxTimeout); + + public abstract Builder totalTimeout(Duration totalTimeout); + + public abstract RetryParamsDefinitionView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ServiceDocView.java b/src/main/java/com/google/api/codegen/viewmodel/ServiceDocView.java new file mode 100644 index 0000000000..3c1a906718 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ServiceDocView.java @@ -0,0 +1,60 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class ServiceDocView { + + public abstract String firstLine(); + + public abstract List remainingLines(); + + public abstract ApiMethodView exampleApiMethod(); + + public abstract String apiVarName(); + + public abstract String apiClassName(); + + public abstract String settingsVarName(); + + public abstract String settingsClassName(); + + public static Builder newBuilder() { + return new AutoValue_ServiceDocView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder firstLine(String val); + + public abstract Builder remainingLines(List val); + + public abstract Builder exampleApiMethod(ApiMethodView val); + + public abstract Builder apiVarName(String val); + + public abstract Builder apiClassName(String val); + + public abstract Builder settingsVarName(String val); + + public abstract Builder settingsClassName(String val); + + public abstract ServiceDocView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/SettingsDocView.java b/src/main/java/com/google/api/codegen/viewmodel/SettingsDocView.java new file mode 100644 index 0000000000..f1226bc211 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/SettingsDocView.java @@ -0,0 +1,61 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class SettingsDocView { + public abstract String serviceAddress(); + + public abstract Integer servicePort(); + + public abstract String exampleApiMethodName(); + + public abstract String exampleApiMethodSettingsGetter(); + + public abstract String apiClassName(); + + public abstract String settingsVarName(); + + public abstract String settingsClassName(); + + public abstract String settingsBuilderVarName(); + + public static Builder newBuilder() { + return new AutoValue_SettingsDocView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder serviceAddress(String val); + + public abstract Builder servicePort(Integer val); + + public abstract Builder exampleApiMethodName(String val); + + public abstract Builder exampleApiMethodSettingsGetter(String val); + + public abstract Builder apiClassName(String val); + + public abstract Builder settingsVarName(String val); + + public abstract Builder settingsClassName(String val); + + public abstract Builder settingsBuilderVarName(String val); + + public abstract SettingsDocView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/SimpleInitCodeLineView.java b/src/main/java/com/google/api/codegen/viewmodel/SimpleInitCodeLineView.java new file mode 100644 index 0000000000..3c76b784fc --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/SimpleInitCodeLineView.java @@ -0,0 +1,47 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.codegen.metacode.InitCodeLineType; +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class SimpleInitCodeLineView implements InitCodeLineView { + + public abstract InitCodeLineType lineType(); + + public abstract String typeName(); + + public abstract String identifier(); + + public abstract InitValueView initValue(); + + public static Builder newBuilder() { + return new AutoValue_SimpleInitCodeLineView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder lineType(InitCodeLineType val); + + public abstract Builder typeName(String val); + + public abstract Builder identifier(String val); + + public abstract Builder initValue(InitValueView val); + + public abstract SimpleInitCodeLineView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/SimpleInitValueView.java b/src/main/java/com/google/api/codegen/viewmodel/SimpleInitValueView.java new file mode 100644 index 0000000000..f551fa8c2c --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/SimpleInitValueView.java @@ -0,0 +1,38 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class SimpleInitValueView implements InitValueView { + + public abstract String initialValue(); + + public String type() { + return SimpleInitValueView.class.getSimpleName(); + } + + public static Builder newBuilder() { + return new AutoValue_SimpleInitValueView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder initialValue(String val); + + public abstract SimpleInitValueView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/SimpleParamDocView.java b/src/main/java/com/google/api/codegen/viewmodel/SimpleParamDocView.java new file mode 100644 index 0000000000..08adcec9c2 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/SimpleParamDocView.java @@ -0,0 +1,51 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class SimpleParamDocView implements ParamDocView { + public abstract String paramName(); + + public abstract String typeName(); + + public abstract String firstLine(); + + public abstract List remainingLines(); + + public String type() { + return SimpleParamDocView.class.getSimpleName(); + } + + public static Builder newBuilder() { + return new AutoValue_SimpleParamDocView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder paramName(String val); + + public abstract Builder typeName(String val); + + public abstract Builder firstLine(String val); + + public abstract Builder remainingLines(List val); + + public abstract SimpleParamDocView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/StaticApiMethodView.java b/src/main/java/com/google/api/codegen/viewmodel/StaticApiMethodView.java new file mode 100644 index 0000000000..8a6202efb7 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/StaticApiMethodView.java @@ -0,0 +1,110 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +import java.util.List; + +import javax.annotation.Nullable; + +/** + * View of a single api method. This is a union class that is capable of holding the + * data for any type of static api method; the type is maintained as a value of the + * ApiMethodType enum. + */ +@AutoValue +public abstract class StaticApiMethodView implements ApiMethodView { + public abstract ApiMethodType type(); + + public abstract String apiClassName(); + + public abstract String apiVariableName(); + + public abstract InitCodeView initCode(); + + public abstract ApiMethodDocView doc(); + + public abstract String apiRequestTypeName(); + + public abstract String responseTypeName(); + + public abstract String name(); + + public abstract String settingsGetterName(); + + public abstract List methodParams(); + + public abstract List pathTemplateChecks(); + + public abstract boolean hasReturnValue(); + + public abstract List requestObjectParams(); + + @Nullable + public abstract ListMethodDetailView listMethod(); + + @Nullable + public abstract UnpagedListCallableMethodDetailView unpagedListCallableMethod(); + + @Nullable + public abstract CallableMethodDetailView callableMethod(); + + @Nullable + public abstract RequestObjectMethodDetailView requestObjectMethod(); + + public static Builder newBuilder() { + return new AutoValue_StaticApiMethodView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder type(ApiMethodType type); + + public abstract Builder apiClassName(String apiClassName); + + public abstract Builder apiVariableName(String apiVariableName); + + public abstract Builder initCode(InitCodeView initCode); + + public abstract Builder doc(ApiMethodDocView doc); + + public abstract Builder apiRequestTypeName(String requestTypeName); + + public abstract Builder responseTypeName(String responseTypeName); + + public abstract Builder name(String name); + + public abstract Builder settingsGetterName(String name); + + public abstract Builder methodParams(List methodParams); + + public abstract Builder pathTemplateChecks(List pathTemplateChecks); + + public abstract Builder hasReturnValue(boolean hasReturnValue); + + public abstract Builder requestObjectParams(List requestObjectParams); + + public abstract Builder listMethod(ListMethodDetailView details); + + public abstract Builder unpagedListCallableMethod(UnpagedListCallableMethodDetailView details); + + public abstract Builder callableMethod(CallableMethodDetailView details); + + public abstract Builder requestObjectMethod(RequestObjectMethodDetailView details); + + public abstract StaticApiMethodView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/StaticXApiView.java b/src/main/java/com/google/api/codegen/viewmodel/StaticXApiView.java new file mode 100644 index 0000000000..095d278fc2 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/StaticXApiView.java @@ -0,0 +1,87 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.codegen.SnippetSetRunner; +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class StaticXApiView implements ViewModel { + @Override + public abstract String templateFileName(); + + public abstract String packageName(); + + public abstract ServiceDocView doc(); + + public abstract String name(); + + public abstract String settingsClassName(); + + public abstract List apiCallableMembers(); + + public abstract List pathTemplates(); + + public abstract List formatResourceFunctions(); + + public abstract List parseResourceFunctions(); + + public abstract List apiMethods(); + + public abstract List imports(); + + @Override + public abstract String outputPath(); + + @Override + public String resourceRoot() { + return SnippetSetRunner.SNIPPET_RESOURCE_ROOT; + } + + public static Builder newBuilder() { + return new AutoValue_StaticXApiView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder templateFileName(String val); + + public abstract Builder packageName(String val); + + public abstract Builder doc(ServiceDocView val); + + public abstract Builder name(String val); + + public abstract Builder settingsClassName(String val); + + public abstract Builder apiCallableMembers(List val); + + public abstract Builder pathTemplates(List val); + + public abstract Builder formatResourceFunctions(List val); + + public abstract Builder parseResourceFunctions(List val); + + public abstract Builder apiMethods(List val); + + public abstract Builder imports(List val); + + public abstract Builder outputPath(String val); + + public abstract StaticXApiView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/StaticXSettingsView.java b/src/main/java/com/google/api/codegen/viewmodel/StaticXSettingsView.java new file mode 100644 index 0000000000..3d99d061db --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/StaticXSettingsView.java @@ -0,0 +1,94 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.codegen.SnippetSetRunner; +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class StaticXSettingsView implements ViewModel { + public abstract String templateFileName(); + + public abstract String packageName(); + + public abstract SettingsDocView doc(); + + public abstract String name(); + + public abstract String serviceAddress(); + + public abstract Integer servicePort(); + + public abstract Iterable authScopes(); + + public abstract List callSettings(); + + public abstract List pageStreamingDescriptors(); + + public abstract List bundlingDescriptors(); + + public abstract List retryCodesDefinitions(); + + public abstract List retryParamsDefinitions(); + + public abstract List imports(); + + public abstract String outputPath(); + + @Override + public String resourceRoot() { + return SnippetSetRunner.SNIPPET_RESOURCE_ROOT; + } + + public static Builder newBuilder() { + return new AutoValue_StaticXSettingsView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder templateFileName(String val); + + public abstract Builder packageName(String val); + + public abstract Builder doc(SettingsDocView generateSettingsDoc); + + public abstract Builder name(String val); + + public abstract Builder serviceAddress(String val); + + public abstract Builder servicePort(Integer val); + + public abstract Builder authScopes(Iterable val); + + public abstract Builder callSettings(List callSettings); + + public abstract Builder pageStreamingDescriptors( + List generateDescriptorClasses); + + public abstract Builder bundlingDescriptors(List val); + + public abstract Builder retryCodesDefinitions(List val); + + public abstract Builder retryParamsDefinitions(List val); + + public abstract Builder imports(List val); + + public abstract Builder outputPath(String val); + + public abstract StaticXSettingsView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/StructureInitCodeLineView.java b/src/main/java/com/google/api/codegen/viewmodel/StructureInitCodeLineView.java new file mode 100644 index 0000000000..389226c681 --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/StructureInitCodeLineView.java @@ -0,0 +1,52 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.api.codegen.metacode.InitCodeLineType; +import com.google.auto.value.AutoValue; + +import java.util.List; + +@AutoValue +public abstract class StructureInitCodeLineView implements InitCodeLineView { + public abstract InitCodeLineType lineType(); + + public abstract String typeName(); + + public abstract String identifier(); + + public abstract List fieldSettings(); + + public abstract InitValueView initValue(); + + public static Builder newBuilder() { + return new AutoValue_StructureInitCodeLineView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder lineType(InitCodeLineType val); + + public abstract Builder typeName(String val); + + public abstract Builder identifier(String val); + + public abstract Builder fieldSettings(List val); + + public abstract Builder initValue(InitValueView val); + + public abstract StructureInitCodeLineView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/UnpagedListCallableMethodDetailView.java b/src/main/java/com/google/api/codegen/viewmodel/UnpagedListCallableMethodDetailView.java new file mode 100644 index 0000000000..373e5a286b --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/UnpagedListCallableMethodDetailView.java @@ -0,0 +1,33 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class UnpagedListCallableMethodDetailView { + public abstract String fnGetResourceListCall(); + + public static Builder newBuilder() { + return new AutoValue_UnpagedListCallableMethodDetailView.Builder(); + } + + @AutoValue.Builder + public static abstract class Builder { + public abstract Builder fnGetResourceListCall(String name); + + public abstract UnpagedListCallableMethodDetailView build(); + } +} diff --git a/src/main/java/com/google/api/codegen/viewmodel/ViewModel.java b/src/main/java/com/google/api/codegen/viewmodel/ViewModel.java new file mode 100644 index 0000000000..fb5bff0cca --- /dev/null +++ b/src/main/java/com/google/api/codegen/viewmodel/ViewModel.java @@ -0,0 +1,28 @@ +/* Copyright 2016 Google Inc + * + * 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 + * + * http://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.viewmodel; + +/** + * Represents a node of a view model that can be rendered by a template + * engine. + */ +public interface ViewModel { + + String resourceRoot(); + + String templateFileName(); + + String outputPath(); +} diff --git a/src/main/resources/com/google/api/codegen/java/common.snip b/src/main/resources/com/google/api/codegen/java/common.snip index 1860288858..6192801030 100644 --- a/src/main/resources/com/google/api/codegen/java/common.snip +++ b/src/main/resources/com/google/api/codegen/java/common.snip @@ -14,118 +14,14 @@ */ @end -@snippet autoGenClassWarning() - // AUTO-GENERATED DOCUMENTATION AND CLASS -@end - -@snippet autoGenServiceWarning() - // AUTO-GENERATED DOCUMENTATION AND SERVICE -@end - -@snippet autoGenMethodWarning() - // AUTO-GENERATED DOCUMENTATION AND METHOD -@end - -@snippet settingsClassName(service) - {@service.getSimpleName}Settings -@end - -@snippet javaDoc(protoElement) - {@javaDocFromStr(getDoc(protoElement))} -@end - -@snippet javaDocFromStr(str) - {@javaDocStart()} - {@javaDocLinesFromStr(str)} - {@javaDocEnd()} -@end - -@snippet javaDocStart() - /** -@end - -@snippet javaDocLines(protoElement) - {@javaDocLinesFromStr(getDoc(protoElement))} -@end - -@snippet javaDocLinesFromStr(str) - @join commentLine : context.java.getJavaDocLines(str) - {@commentLine} +@snippet paramList(params) + @join param : params on ", " + {@param.typeName} {@param.name} @end @end -@snippet javaDocEmptyLine() - {@""} * -@end - -@snippet javaDocThrows() - {@""} * @ throws com.google.api.gax.grpc.ApiException if the remote call fails -@end - -@snippet javaDocEnd() - {@""} */ -@end - -@snippet getDoc(protoElement) - {@context.getDescription(protoElement)} -@end - -@snippet setCallName(field) - {@setCallName(field.getType, context.lowerUnderscoreToUpperCamel(field.getSimpleName))} -@end - -@snippet setCallName(type, name) - @if type.isMap - putAll{@name} - @else - @if type.isRepeated - addAll{@name} - @else - set{@name} - @end - @end -@end - -@snippet getCallName(field) - @let paramNameInCamel = context.lowerUnderscoreToUpperCamel(field.getSimpleName) - @if field.isRepeated - get{@paramNameInCamel}List - @else - get{@paramNameInCamel} - @end - @end -@end - -@snippet getIndexCallName(field) - @let paramNameInCamel = context.lowerUnderscoreToUpperCamel(field.getSimpleName) - @if field.isRepeated - get{@paramNameInCamel} - @else - # TODO(garrettjones) throw snippet error - INVALID - @end +@snippet argList(args) + @join arg : args on ", " + {@arg} @end @end - -@snippet getCountCallName(field) - @let paramNameInCamel = context.lowerUnderscoreToUpperCamel(field.getSimpleName) - @if field.isRepeated - get{@paramNameInCamel}Count - @else - # TODO(garrettjones) throw snippet error - 1 #INVALID - @end - @end -@end - -@snippet formatResourceFunctionName(collectionConfig) - format{@resourceName(collectionConfig)} -@end - -@snippet resourceName(collectionConfig) - {@context.lowerUnderscoreToUpperCamel(collectionConfig.getEntityName)}Name -@end - -@snippet elementTypeName(resourcesField) - {@context.basicTypeNameBoxed(resourcesField.getType())} -@end diff --git a/src/main/resources/com/google/api/codegen/java/main.snip b/src/main/resources/com/google/api/codegen/java/main.snip index 583c522239..534d109627 100644 --- a/src/main/resources/com/google/api/codegen/java/main.snip +++ b/src/main/resources/com/google/api/codegen/java/main.snip @@ -1,268 +1,251 @@ @extends "java/common.snip" @extends "java/method_sample.snip" -@snippet generateFilename(service) - {@context.getApiWrapperName(service)}.java -@end - -@snippet generateClass(service, body, imports) +@snippet generate(xapiClass) {@license()} - package {@context.getApiConfig.getPackageName}; + package {@xapiClass.packageName}; - @join import : imports + @join import : xapiClass.imports import {@import}; @end - {@body} -@end - -@snippet generateBody(service) - {@alwaysImport()} - - {@serviceJavaDoc(service)} + {@serviceDoc(xapiClass)} @@javax.annotation.Generated("by GAPIC") - public class {@context.getApiWrapperName(service)} implements AutoCloseable { - {@members(service)} - - {@resourceUtils(service)} - - {@constructors(service)} - - {@callables(service)} - + public class {@xapiClass.name} implements AutoCloseable { + {@members(xapiClass)} + {@statics(xapiClass)} + {@staticFunctions(xapiClass)} + {@constructors(xapiClass)} + {@apiMethods(xapiClass)} {@cleanupSection()} } @end -@private alwaysImport() fill - {@context.addImport("com.google.api.gax.grpc.ApiCallable")} - {@context.addImport("com.google.api.gax.protobuf.PathTemplate")} - {@context.addImport("io.grpc.ManagedChannel")} - {@context.addImport("java.io.Closeable")} - {@context.addImport("java.io.IOException")} - {@context.addImport("java.util.ArrayList")} - {@context.addImport("java.util.List")} - {@context.addImport("java.util.concurrent.ScheduledExecutorService")} -@end - -@private resourceUtils(service) - {@resourceConstants(service)} - {@resourceFunctions(service)} -@end - -@private resourceConstants(service) - {@pathTemplateConstants(service)} -@end - -@private pathTemplateConstants(service) - @join collectionConfig : context.getApiConfig.getInterfaceConfig(service).getCollectionConfigs() - {@pathTemplateConstant(collectionConfig)} - +@private serviceDoc(xapiClass) + @let coreSampleCode = syncMethodSampleCode(xapiClass.doc.exampleApiMethod), \ + decoratedSampleCode = decorateSampleCode(xapiClass.doc.exampleApiMethod, coreSampleCode) + {@renderServiceDoc(xapiClass.doc, decoratedSampleCode)} @end @end -@private pathTemplateConstant(collectionConfig) - private static final PathTemplate {@pathTemplateConstantName(collectionConfig)} = - PathTemplate.createWithoutUrlEncoding("{@collectionConfig.getNamePattern}"); +@private renderServiceDoc(xapiClassDoc, exampleMethodSampleCode) + // AUTO-GENERATED DOCUMENTATION AND SERVICE + /** + * Service Description: {@xapiClassDoc.firstLine} + @if xapiClassDoc.remainingLines + @join commentLine : xapiClassDoc.remainingLines + {@""} * {@commentLine} + @end + @end + * + *

This class provides the ability to make remote calls to the backing service through method + * calls that map to API methods. Sample code to get started: + * + *

+   * 
+  @join sampleLine : util.getDocLines(exampleMethodSampleCode)
+    {@""} * {@sampleLine}
+  @end
+   * 
+   * 
+ * + *

Note: close() needs to be called on the {@xapiClassDoc.apiVarName} object to clean up resources such + * as threads. In the example above, try-with-resources is used, which automatically calls + * close(). + * + *

The surface of this class includes several types of Java methods for each of the API's methods: + * + *

    + *
  1. A "flattened" method. With this type of method, the fields of the request type have been + * converted into function parameters. It may be the case that not all fields are available + * as parameters, and not every API method will have a flattened method entry point. + *
  2. A "request object" method. This type of method only takes one parameter, a request + * object, which must be constructed before the call. Not every API method will have a request + * object method. + *
  3. A "callable" method. This type of method takes no parameters and returns an immutable + * ApiCallable object, which can be used to initiate calls to the service. + *
+ * + *

See the individual methods for example code. + * + *

Many parameters require resource names to be formatted in a particular way. To assist + * with these names, this class includes a format method for each type of name, and additionally + * a parse method to extract the individual identifiers contained within names that are + * returned. + * + *

This class can be customized by passing in a custom instance of {@xapiClassDoc.settingsClassName} to + * create(). For example: + * + *

+   * 
+   * {@xapiClassDoc.settingsClassName} {@xapiClassDoc.settingsVarName} = {@xapiClassDoc.settingsClassName}.defaultBuilder()
+   *     .provideChannelWith(myCredentials)
+   *     .build();
+   * {@xapiClassDoc.apiClassName} {@xapiClassDoc.apiVarName} = \
+       {@xapiClassDoc.apiClassName}.create({@xapiClassDoc.settingsVarName});
+   * 
+   * 
+ */ @end -@private pathTemplateConstantName(collectionConfig) - {@context.lowerUnderscoreToUpperUnderscore(collectionConfig.getEntityName)}_PATH_TEMPLATE +@private statics(xapiClass) + @join pathTemplate : xapiClass.pathTemplates + private static final PathTemplate {@pathTemplate.name} = + PathTemplate.createWithoutUrlEncoding("{@pathTemplate.pattern}"); + {@""} + @end @end -@private resourceFunctions(service) - @join collectionConfig : context.getApiConfig.getInterfaceConfig(service).getCollectionConfigs() - {@formatResourceFunctions(collectionConfig)} +@private staticFunctions(xapiClass) + @join function : xapiClass.formatResourceFunctions + {@formatResourceFunction(function)} @end - - @join collectionConfig : context.getApiConfig.getInterfaceConfig(service).getCollectionConfigs() - {@parseResourceFunctions(collectionConfig)} + {@""} + @join function : xapiClass.parseResourceFunctions + {@parseResourceFunction(function)} @end @end -@private formatResourceFunctions(collectionConfig) +@private formatResourceFunction(function) /** * Formats a string containing the fully-qualified path to represent - * a {@collectionConfig.getEntityName} resource. + * a {@function.entityName} resource. */ - public static final String {@formatResourceFunctionName(collectionConfig)}(\ - {@formatResourceFunctionParams(collectionConfig)}) { - return {@pathTemplateConstantName(collectionConfig)}.instantiate( - {@pathTemplateArgs(collectionConfig)}); + public static final String {@function.name}(\ + {@formatResourceFunctionParams(function.resourceIdParams)}) { + return {@function.pathTemplateName}.instantiate( + {@pathTemplateArgs(function.resourceIdParams)}); } - + {@""} @end -@private formatResourceFunctionParams(collectionConfig) - @join param : collectionConfig.getNameTemplate.vars() on ", " - String {@context.lowerUnderscoreToLowerCamel(param)} +@private formatResourceFunctionParams(resourceIdParams) + @join param : resourceIdParams on ", " + String {@param.name} @end @end -@private pathTemplateArgs(collectionConfig) - @join param : collectionConfig.getNameTemplate.vars() vertical on "," - "{@param}", {@context.lowerUnderscoreToLowerCamel(param)} +@private pathTemplateArgs(resourceIdParams) + @join param : resourceIdParams on ",".add(BREAK) + "{@param.templateKey}", {@param.name} @end @end -@private parseResourceFunctions(collectionConfig) - @join subField : collectionConfig.getNameTemplate.vars() - @let fieldPath = context.upperCamelToLowerCamel(resourceName(collectionConfig)) - /** - * Parses the {@subField} from the given fully-qualified path which - * represents a {@context.lowerUnderscoreToLowerCamel(collectionConfig.getEntityName)} resource. - */ - public static final String \ - parse{@context.lowerUnderscoreToUpperCamel(subField)}From{@resourceName(collectionConfig)}(\ - String {@fieldPath}) { - return {@pathTemplateConstantName(collectionConfig)}.parse({@fieldPath}).get("{@subField}"); - } - - @end - @end +@private parseResourceFunction(function) + /** + * Parses the {@function.outputResourceId} from the given fully-qualified path which + * represents a {@function.entityName} resource. + */ + public static final String {@function.name}(String {@function.entityNameParamName}) { + return {@function.pathTemplateName}.parse({@function.entityNameParamName})\ + .get("{@function.outputResourceId}"); + } + {@""} @end -@private members(service) - private final {@settingsClassName(service)} settings; +@private members(xapiClass) + private final {@xapiClass.settingsClassName} settings; private final ManagedChannel channel; private final ScheduledExecutorService executor; private final List closeables = new ArrayList<>(); - @join method : service.getMethods - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - inTypeName = context.typeName(method.getInputType), \ - outTypeName = context.typeName(method.getOutputType), \ - isPageStreaming = methodConfig.isPageStreaming - private final ApiCallable<{@inTypeName}, {@outTypeName}> {@methodName}Callable; - @if {@isPageStreaming} - @let pageStreaming = methodConfig.getPageStreaming(), \ - resourceTypeName = context.basicTypeNameBoxed(pageStreaming.getResourcesField().getType()), \ - dummy = context.addImport("com.google.api.gax.core.PageAccessor") - private final ApiCallable<{@inTypeName}, PageAccessor<{@resourceTypeName}>> - {@methodName}PagedCallable; - @end - @end - @end + @join apiCallable : xapiClass.apiCallableMembers + private final ApiCallable<{@apiCallable.requestTypeName}, {@apiCallable.responseTypeName}> {@apiCallable.name}; @end - public final {@settingsClassName(service)} getSettings() { + public final {@xapiClass.settingsClassName} getSettings() { return settings; } + {@""} @end -@private constructors(service) - @let className = context.getApiWrapperName(service) - /** - * Constructs an instance of {@className} with default settings. - */ - public static final {@className} createWithDefaults() throws IOException { - return create({@settingsClassName(service)}.defaultBuilder().build()); - } +@private constructors(xapiClass) + /** + * Constructs an instance of {@xapiClass.name} with default settings. + */ + public static final {@xapiClass.name} createWithDefaults() throws IOException { + return create({@xapiClass.settingsClassName}.defaultBuilder().build()); + } - /** - * Constructs an instance of {@className}, using the given settings. - * The channels are created based on the settings passed in, or defaults for any - * settings that are not set. - */ - public static final {@className} create({@settingsClassName(service)} settings) throws IOException { - return new {@className}(settings); - } + /** + * Constructs an instance of {@xapiClass.name}, using the given settings. + * The channels are created based on the settings passed in, or defaults for any + * settings that are not set. + */ + public static final {@xapiClass.name} create({@xapiClass.settingsClassName} settings) throws IOException { + return new {@xapiClass.name}(settings); + } - /** - * Constructs an instance of {@className}, using the given settings. - * This is protected so that it easy to make a subclass, but otherwise, the static - * factory methods should be preferred. - */ - protected {@className}({@settingsClassName(service)} settings) throws IOException { - this.settings = settings; - this.executor = settings.getExecutorProvider().getOrBuildExecutor(); - this.channel = settings.getChannelProvider().getOrBuildChannel(this.executor); - - @join method : service.getMethods - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - isPageStreaming = methodConfig.isPageStreaming, \ - isBundling = methodConfig.isBundling - this.{@methodName}Callable = ApiCallable.create(settings.{@methodName}Settings(), this.channel, this.executor); - @if {@isPageStreaming} - this.{@methodName}PagedCallable = - ApiCallable.createPagedVariant(settings.{@methodName}Settings(), this.channel, this.executor); - @end - @if {@isBundling} - if (settings.{@methodName}Settings().getBundlerFactory() != null) { - closeables.add(settings.{@methodName}Settings().getBundlerFactory()); - } - @end - @end + /** + * Constructs an instance of {@xapiClass.name}, using the given settings. + * This is protected so that it easy to make a subclass, but otherwise, the static + * factory methods should be preferred. + */ + protected {@xapiClass.name}({@xapiClass.settingsClassName} settings) throws IOException { + this.settings = settings; + this.executor = settings.getExecutorProvider().getOrBuildExecutor(); + this.channel = settings.getChannelProvider().getOrBuildChannel(this.executor); + + @join apiCallable : xapiClass.apiCallableMembers + @switch apiCallable.type.toString + @case "SimpleApiCallable" + this.{@apiCallable.name} = ApiCallable.create(settings.{@apiCallable.settingsFunctionName}(), this.channel, this.executor); + @case "PagedApiCallable" + this.{@apiCallable.name} = + ApiCallable.createPagedVariant(settings.{@apiCallable.settingsFunctionName}(), this.channel, this.executor); + @case "BundlingApiCallable" + this.{@apiCallable.name} = ApiCallable.create(settings.{@apiCallable.settingsFunctionName}(), this.channel, this.executor); + if (settings.{@apiCallable.settingsFunctionName}().getBundlerFactory() != null) { + closeables.add(settings.{@apiCallable.settingsFunctionName}().getBundlerFactory()); + } + @default + $unhandledCase: {@apiCallable.type.toString}$ @end + @end - if (settings.getChannelProvider().shouldAutoClose()) { - closeables.add( - new Closeable() { - @@Override - public void close() throws IOException { - channel.shutdown(); - } - }); - } - if (settings.getExecutorProvider().shouldAutoClose()) { - closeables.add( - new Closeable() { - @@Override - public void close() throws IOException { - executor.shutdown(); - } - }); - } + if (settings.getChannelProvider().shouldAutoClose()) { + closeables.add( + new Closeable() { + @@Override + public void close() throws IOException { + channel.shutdown(); + } + }); } - @end -@end - -@private callables(service) - @join method : service.getMethods - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - inTypeName = context.typeName(method.getInputType), \ - outTypeName = context.typeName(method.getOutputType), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - isPageStreaming = methodConfig.isPageStreaming, \ - isFlattening = methodConfig.isFlattening, \ - requestObjectMethodAccessStr = requestObjectMethodAccess(methodConfig) - // ----- {@methodName} ----- - - # TODO (garrettjones) put some kind of limit on number of flattened parameters, and - # don't generated a flattened method if there are too many. - @if {@isPageStreaming} - @if {@isFlattening} - @join flatteningGroup: \ - methodConfig.getFlattening().getFlatteningGroups() - {@pagedFlattenedMethod(service, method, methodName, flatteningGroup)} - @end - {@BREAK} - @end - {@pagedMethodWithRequestParam(service, method, methodName, inTypeName, outTypeName, requestObjectMethodAccessStr)} - {@methodReturningPagedCallable(service, method, methodName, inTypeName, outTypeName)} - {@methodReturningUnpagedListCallable(service, method, methodName, inTypeName, outTypeName)} - @else - @if {@isFlattening} - @join flatteningGroup : \ - methodConfig.getFlattening().getFlatteningGroups() - {@flattenedMethod(service, method, methodName, flatteningGroup)} - @end - {@BREAK} - @end - {@methodWithRequestParam(service, method, methodName, inTypeName, outTypeName, requestObjectMethodAccessStr)} - {@methodReturningCallable(service, method, methodName, inTypeName, outTypeName)} - @end + if (settings.getExecutorProvider().shouldAutoClose()) { + closeables.add( + new Closeable() { + @@Override + public void close() throws IOException { + executor.shutdown(); + } + }); + } + } + {@""} +@end + +@private apiMethods(xapiClass) + @join apiMethod : xapiClass.apiMethods + @switch apiMethod.type.toString + @case "PagedFlattenedMethod" + {@pagedFlattenedMethod(apiMethod)} + @case "PagedRequestObjectMethod" + {@pagedRequestObjectMethod(apiMethod)} + @case "PagedCallableMethod" + {@pagedCallableMethod(apiMethod)} + @case "UnpagedListCallableMethod" + {@unpagedListCallableMethod(apiMethod)} + @case "FlattenedMethod" + {@flattenedMethod(apiMethod)} + @case "RequestObjectMethod" + {@requestObjectMethod(apiMethod)} + @case "CallableMethod" + {@callableMethod(apiMethod)} + @default + $unhandledCase: {@apiMethod.getClass.getSimpleName}$ @end - @end -@end - -@private requestObjectMethodAccess(methodConfig) - @if {@methodConfig.hasRequestObjectMethod} - public - @else - private + {@BREAK} @end @end @@ -280,306 +263,148 @@ @end -@private pagedFlattenedMethod(service, method, methodName, fields) - @let methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - pageStreaming = methodConfig.getPageStreaming(), \ - resourceTypeName = elementTypeName(pageStreaming.getResourcesField()), \ - requestTypeName = context.typeName(method.getInputType), \ - fieldNamePatterns = methodConfig.getFieldNamePatterns() - {@iterableFlattenedMethodJavaDoc(service, method, methodName, resourceTypeName, fields)} - public final PageAccessor<{@resourceTypeName}> \ - {@methodName}({@paramList(fields)}) { - @join field : fields - @if fieldNamePatterns.containsKey(field.getSimpleName) - @let entityName = fieldNamePatterns.get(field.getSimpleName), \ - collectionConfig = context.getCollectionConfig(service, entityName) - {@pathTemplateCheck(paramName(field), collectionConfig)} - @end - @end - @end - {@context.typeName(method.getInputType)} request = - {@requestTypeName}.newBuilder() - {@builderSetCalls(fields)} - .build(); - return {@methodName}(request); - } - +@private pagedFlattenedMethod(apiMethod) + @let coreSampleCode = pagedIterableMethodSampleCode(apiMethod) + {@methodDoc(apiMethod.doc, decorateSampleCode(apiMethod, coreSampleCode))} @end + public final {@apiMethod.responseTypeName} {@apiMethod.name}({@paramList(apiMethod.methodParams)}) { + @join pathTemplateCheck : apiMethod.pathTemplateChecks + {@pathTemplateCheckLine(pathTemplateCheck)} + @end + {@apiMethod.apiRequestTypeName} request = + {@apiMethod.apiRequestTypeName}.newBuilder() + {@builderSetCalls(apiMethod.requestObjectParams)} + .build(); + return {@apiMethod.name}(request); + } @end -@private pagedMethodWithRequestParam(service, method, methodName, inTypeName, outTypeName, accessModifier) - @let methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - pageStreaming = methodConfig.getPageStreaming(), \ - resourceTypeName = elementTypeName(pageStreaming.getResourcesField()) - {@methodJavaDoc(method, context.newJavaDocConfigBuilder \ - .setApiName(context.getApiWrapperName(method.getParent)) \ - .setMethodName(methodName) \ - .setReturnType(resourceTypeName) \ - .setRequestObjectInitCode(context, service, method) \ - .setRequestObjectParam(method) \ - .setPagedVariant({@TRUE}) \ - .setCallableVariant({@FALSE}) \ - .build)} - {@accessModifier} final PageAccessor<{@resourceTypeName}> {@methodName}({@inTypeName} request) { - return {@methodName}PagedCallable() - .call(request); - } - +@private pagedRequestObjectMethod(apiMethod) + @let coreSampleCode = pagedIterableMethodSampleCode(apiMethod) + {@methodDoc(apiMethod.doc, decorateSampleCode(apiMethod, coreSampleCode))} @end + {@apiMethod.requestObjectMethod.accessModifier} final {@apiMethod.responseTypeName} \ + {@apiMethod.name}({@apiMethod.apiRequestTypeName} request) { + return {@apiMethod.requestObjectMethod.callableMethodName}() + .call(request); + } @end -@private methodReturningPagedCallable(service, method, methodName, inTypeName, outTypeName) - @let methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - pageStreaming = methodConfig.getPageStreaming(), \ - dummy = context.addImport("com.google.api.gax.core.PageAccessor"), \ - resourceTypeName = elementTypeName(pageStreaming.getResourcesField()) - {@methodJavaDoc(method, context.newJavaDocConfigBuilder \ - .setApiName(context.getApiWrapperName(method.getParent)) \ - .setMethodName(methodName) \ - .setReturnType(resourceTypeName) \ - .setRequestObjectInitCode(context, service, method) \ - .setEmptyParams() \ - .setPagedVariant({@TRUE}) \ - .setCallableVariant({@TRUE}) \ - .build)} - public final ApiCallable<{@inTypeName}, PageAccessor<{@resourceTypeName}>> {@methodName}PagedCallable() { - return {@methodName}PagedCallable; - } - +@private pagedCallableMethod(apiMethod) + @let coreSampleCode = pagedCallableMethodSampleCode(apiMethod) + {@methodDoc(apiMethod.doc, decorateSampleCode(apiMethod, coreSampleCode))} @end + {@callableMethodImpl(apiMethod)} @end -@private methodReturningUnpagedListCallable(service, method, methodName, inTypeName, outTypeName) - @let methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - pageStreaming = methodConfig.getPageStreaming(), \ - dummy = context.addImport("com.google.api.gax.core.PageAccessor"), \ - resourcesField = pageStreaming.getResourcesField() - {@methodJavaDoc(method, context.newJavaDocConfigBuilder \ - .setApiName(context.getApiWrapperName(method.getParent)) \ - .setMethodName(methodName) \ - .setReturnType(context.returnTypeOrEmpty(method.getOutputType)) \ - .setRequestObjectInitCode(context, service, method) \ - .setEmptyParams() \ - .setPagedVariant({@FALSE}) \ - .setCallableVariant({@TRUE}) \ - .setResourcesFieldForUnpagedListCallable(resourcesField) \ - .build)} - public final ApiCallable<{@inTypeName}, {@outTypeName}> {@methodName}Callable() { - return {@methodName}Callable; - } - +@private unpagedListCallableMethod(apiMethod) + @let coreSampleCode = unpagedListCallableMethodSampleCode(apiMethod) + {@methodDoc(apiMethod.doc, decorateSampleCode(apiMethod, coreSampleCode))} @end + {@callableMethodImpl(apiMethod)} @end -@private flattenedMethod(service, method, methodName, fields) - {@flattenedMethodJavaDoc(service, method, methodName, fields)} - @let methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - returnType = context.methodReturnTypeName(method.getOutputType), \ - returnStatement = context.methodReturnStatement(method.getOutputType), \ - requestTypeName = context.typeName(method.getInputType), \ - fieldNamePatterns = methodConfig.getFieldNamePatterns() - public final {@returnType} {@methodName}({@paramList(fields)}) { - @join field : fields - @if fieldNamePatterns.containsKey(field.getSimpleName) - @let entityName = fieldNamePatterns.get(field.getSimpleName), \ - collectionConfig = context.getCollectionConfig(service, entityName) - {@pathTemplateCheck(paramName(field), collectionConfig)} - @end - @end - @end - {@context.typeName(method.getInputType)} request = - {@requestTypeName}.newBuilder() - {@builderSetCalls(fields)} - .build(); - {@returnStatement}{@methodName}(request); - } - +@private flattenedMethod(apiMethod) + @let coreSampleCode = syncMethodSampleCode(apiMethod) + {@methodDoc(apiMethod.doc, decorateSampleCode(apiMethod, coreSampleCode))} @end + public final {@apiMethod.responseTypeName} {@apiMethod.name}(\ + {@paramList(apiMethod.methodParams)}) { + @join pathTemplateCheck : apiMethod.pathTemplateChecks + {@pathTemplateCheckLine(pathTemplateCheck)} + @end + {@apiMethod.apiRequestTypeName} request = + {@apiMethod.apiRequestTypeName}.newBuilder() + {@builderSetCalls(apiMethod.requestObjectParams)} + .build(); + @if apiMethod.hasReturnValue + return {@apiMethod.name}(request); + @else + {@apiMethod.name}(request); + @end + } @end -@private methodWithRequestParam(service, method, methodName, inTypeName, outTypeName, accessModifier) - {@methodJavaDoc(method, context.newJavaDocConfigBuilder \ - .setApiName(context.getApiWrapperName(method.getParent)) \ - .setMethodName(context.upperCamelToLowerCamel(method.getSimpleName)) \ - .setReturnType(context.returnTypeOrEmpty(method.getOutputType)) \ - .setRequestObjectInitCode(context, service, method) \ - .setRequestObjectParam(method) \ - .setPagedVariant({@FALSE}) \ - .setCallableVariant({@FALSE}) \ - .build)} - @let returnType = context.methodReturnTypeName(method.getOutputType), \ - returnStatement = context.methodReturnStatement(method.getOutputType) - {@accessModifier} {@returnType} {@methodName}({@inTypeName} request) { - {@returnStatement}{@methodName}Callable().call(request); - } - +@private requestObjectMethod(apiMethod) + @let coreSampleCode = syncMethodSampleCode(apiMethod) + {@methodDoc(apiMethod.doc, decorateSampleCode(apiMethod, coreSampleCode))} @end -@end - -@private methodReturningCallable(service, method, methodName, inTypeName, outTypeName) - {@methodJavaDoc(method, context.newJavaDocConfigBuilder \ - .setApiName(context.getApiWrapperName(method.getParent)) \ - .setMethodName(methodName) \ - .setReturnType(context.returnTypeOrEmpty(method.getOutputType)) \ - .setRequestObjectInitCode(context, service, method) \ - .setEmptyParams() \ - .setPagedVariant({@FALSE}) \ - .setCallableVariant({@TRUE}) \ - .build)} - public final ApiCallable<{@inTypeName}, {@outTypeName}> {@methodName}Callable() { - return {@methodName}Callable; + {@apiMethod.requestObjectMethod.accessModifier} final {@apiMethod.responseTypeName} \ + {@apiMethod.name}({@apiMethod.apiRequestTypeName} request) { + @if apiMethod.hasReturnValue + return {@apiMethod.requestObjectMethod.callableMethodName}().call(request); + @else + {@apiMethod.requestObjectMethod.callableMethodName}().call(request); + @end } - @end -@private serviceJavaDoc(service) - {@autoGenServiceWarning()} - @let serviceApiVariable = context.upperCamelToLowerCamel(context.getApiWrapperName(service)), \ - settingsVariable = context.upperCamelToLowerCamel(settingsClassName(service)), \ - # TODO: support the case where the API has no flattened methods. - firstFlattenedMethod = context.getFirstFlattenedMethod(service), \ - firstFlattenedMethodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(firstFlattenedMethod), \ - fields = firstFlattenedMethodConfig.getFlattening().getFlatteningGroups().get(0) - /** - {@javaDocLinesFromStr(serviceDocString(service))} - * - *

This class provides the ability to make remote calls to the backing service through method - * calls that map to API methods. Sample code to get started: - * - *

-     * 
-    @join commentLine : context.java.getJavaDocLines(generateMethodSampleCode(context.newJavaDocConfigBuilder \
-                               .setApiName(context.getApiWrapperName(service)) \
-                               .setMethodName(context.upperCamelToLowerCamel(firstFlattenedMethod.getSimpleName)) \
-                               .setReturnType(context.returnTypeOrEmpty(firstFlattenedMethod.getOutputType)) \
-                               .setFieldInitCode(context, service, firstFlattenedMethod, fields) \
-                               .setFieldParams(context, fields) \
-                               .setPagedVariant({@FALSE}) \
-                               .setCallableVariant({@FALSE}) \
-                               .build))
-      {@commentLine}
-    @end
-     * 
-     * 
- * - *

Note: close() needs to be called on the {@serviceApiVariable} object to clean up resources such - * as threads. In the example above, try-with-resources is used, which automatically calls - * close(). - * - *

The surface of this class includes several types of Java methods for each of the API's methods: - * - *

    - *
  1. A "flattened" method. With this type of method, the fields of the request type have been - * converted into function parameters. It may be the case that not all fields are available - * as parameters, and not every API method will have a flattened method entry point. - *
  2. A "request object" method. This type of method only takes one parameter, a request - * object, which must be constructed before the call. Not every API method will have a request - * object method. - *
  3. A "callable" method. This type of method takes no parameters and returns an immutable - * ApiCallable object, which can be used to initiate calls to the service. - *
- * - *

See the individual methods for example code. - * - *

Many parameters require resource names to be formatted in a particular way. To assist - * with these names, this class includes a format method for each type of name, and additionally - * a parse method to extract the individual identifiers contained within names that are - * returned. - * - *

This class can be customized by passing in a custom instance of {@settingsClassName(service)} to - * create(). For example: - * - *

-     * 
-     * {@settingsClassName(service)} {@settingsVariable} = {@settingsClassName(service)}.defaultBuilder()
-     *     .provideChannelWith(myCredentials)
-     *     .build();
-     * {@context.getApiWrapperName(service)} {@serviceApiVariable} = \
-         {@context.getApiWrapperName(service)}.create({@settingsVariable});
-     * 
-     * 
- */ +@private callableMethod(apiMethod) + @let coreSampleCode = callableMethodSampleCode(apiMethod) + {@methodDoc(apiMethod.doc, decorateSampleCode(apiMethod, coreSampleCode))} @end + {@callableMethodImpl(apiMethod)} @end -@snippet serviceDocString(protoElement) - Service Description: {@getDoc(protoElement)} -@end - -@private flattenedMethodJavaDoc(service, method, methodName, fields) - {@methodJavaDoc(method, context.newJavaDocConfigBuilder \ - .setApiName(context.getApiWrapperName(method.getParent)) \ - .setMethodName(methodName) \ - .setReturnType(context.returnTypeOrEmpty(method.getOutputType)) \ - .setFieldInitCode(context, service, method, fields) \ - .setFieldParams(context, fields) \ - .setPagedVariant({@FALSE}) \ - .setCallableVariant({@FALSE}) \ - .build)} -@end - -@private iterableFlattenedMethodJavaDoc(service, method, methodName, resourceName, fields) - {@methodJavaDoc(method, context.newJavaDocConfigBuilder \ - .setApiName(context.getApiWrapperName(method.getParent)) \ - .setMethodName(methodName) \ - .setReturnType(resourceName) \ - .setFieldInitCode(context, service, method, fields) \ - .setFieldParams(context, fields) \ - .setPagedVariant({@TRUE}) \ - .setCallableVariant({@FALSE}) \ - .build)} +@private callableMethodImpl(apiMethod) + public final ApiCallable<{@apiMethod.apiRequestTypeName}, {@apiMethod.responseTypeName}> \ + {@apiMethod.name}() { + return {@apiMethod.callableMethod.callableName}; + } @end -@private methodJavaDoc(method, docConfig) - {@autoGenMethodWarning()} - {@javaDocStart()} - {@javaDocLines(method)} - @if context.getApiConfig.generateSamples - {@javaDocEmptyLine()} - {@javaDocEmptyLine()} Sample code: - {@javaDocEmptyLine()}

-    @join commentLine : context.java.getJavaDocLines(generateMethodSampleCode(docConfig))
-      {@commentLine}
+@private methodDoc(apiMethodDoc, methodSampleCode)
+  // AUTO-GENERATED DOCUMENTATION AND METHOD
+  /**
+  @join commentLine : apiMethodDoc.mainDocLines
+    {@""} * {@commentLine} 
+  @end
+   *
+   * Sample code:
+   * 

+  @join sampleLine : util.getDocLines(methodSampleCode)
+    {@""} * {@sampleLine}
+  @end
+   * 
+ @if apiMethodDoc.paramDocs + {@""} * + @join doc : apiMethodDoc.paramDocs + {@paramDoc(doc)} @end - {@javaDocEmptyLine()}
@end - @if docConfig.isCallableVariant - @else - {@javaDocEmptyLine()} - @join param : docConfig.getParams - @join commentLine : context.java.getJavaDocLinesWithPrefix(param.getDescription, paramDocLinePrefix(param)) - {@commentLine} - @end + @if apiMethodDoc.throwsDocLines + @join commentLine : apiMethodDoc.throwsDocLines + {@""} * {@commentLine} @end - {@javaDocThrows()} @end - {@javaDocEnd()} + */ + {@EMPTY} @end -@private paramDocLinePrefix(param) - @@param {@param.getName} {@""} +@private paramDoc(doc) + @switch doc.type + @case "SimpleParamDocView" + {@simpleParamDoc(doc)} + @default + $unhandledCase: {@doc.type}$ + @end @end -@private paramList(fields) - @join field : fields on ", " - @let paramName = context.lowerUnderscoreToLowerCamel(field.getSimpleName) - {@context.typeName(field.getType)} {@paramName} +@private simpleParamDoc(doc) + {@""} * @@param {@doc.paramName} {@doc.firstLine} + @if doc.remainingLines + @join commentLine : doc.remainingLines + {@""} * {@commentLine} @end @end @end -@private paramName(field) - {@context.lowerUnderscoreToLowerCamel(field.getSimpleName)} -@end - -@private builderSetCalls(fields) - @join field : fields - @let paramName = context.lowerUnderscoreToLowerCamel(field.getSimpleName) - .{@setCallName(field)}({@paramName}) - @end +@private builderSetCalls(requestObjectParams) + @join requestObjectParam : requestObjectParams + .{@requestObjectParam.setCallName}({@requestObjectParam.name}) @end @end -@snippet pathTemplateCheck(paramName, collectionConfig) - {@pathTemplateConstantName(collectionConfig)}.validate({@paramName}); +@private pathTemplateCheckLine(pathTemplateCheck) + {@pathTemplateCheck.pathTemplateName}.validate({@pathTemplateCheck.paramName}); @end diff --git a/src/main/resources/com/google/api/codegen/java/method_sample.snip b/src/main/resources/com/google/api/codegen/java/method_sample.snip index c2d955f5ed..0ce04c3b3a 100644 --- a/src/main/resources/com/google/api/codegen/java/method_sample.snip +++ b/src/main/resources/com/google/api/codegen/java/method_sample.snip @@ -1,61 +1,86 @@ @extends "java/common.snip" -# Generate code samples for method-level documentation. -@snippet generateMethodSampleCode(docConfig) - @let ApiName = docConfig.getApiName, \ - apiName = context.upperCamelToLowerCamel(ApiName) - try ({@ApiName} {@apiName} = {@ApiName}.createWithDefaults()) { - {@initCode(docConfig.getInitCode)} - @if docConfig.isUnpagedListCallableVariant - @let resourcesField = docConfig.getResourcesFieldForUnpagedListCallable - while (true) { - {@callResultSampleCode(docConfig.getReturnType)}{@methodCallSampleCode(docConfig, apiName)}; - for ({@elementTypeName(resourcesField)} elements : response.{@getResourcesListCall(resourcesField)}) { - // doThingsWith(elements); - } - String nextPageToken = response.getNextPageToken(); - if (!Strings.isNullOrEmpty(nextPageToken)) { - request = request.toBuilder().setPageToken(nextPageToken).build(); - } else { - break; - } - } - @end - @else - @if docConfig.isCallableVariant - ListenableFuture<{@getGenericAwareReturnType(docConfig)}> future = {@methodFutureCall(docConfig, apiName)}; - // Do something{@BREAK} - @end - @if docConfig.isPagedVariant - for ({@docConfig.getReturnType} elements : {@methodCallSampleCode(docConfig, apiName)}) { - // doThingsWith(elements); - } - @else - {@callResultSampleCode(docConfig.getReturnType)}{@methodCallSampleCode(docConfig, apiName)}; - @end - @end +@snippet decorateSampleCode(apiMethod, coreSampleCode) + try ({@apiMethod.apiClassName} {@apiMethod.apiVariableName} = \ + {@apiMethod.apiClassName}.createWithDefaults()) { + {@coreSampleCode} + } +@end + +@snippet pagedIterableMethodSampleCode(apiMethod) + {@initCode(apiMethod.initCode)} + for ({@apiMethod.listMethod.resourceTypeName} element : {@sampleSyncMethodCall(apiMethod)}) { + // doThingsWith(element); + } +@end + +@snippet pagedCallableMethodSampleCode(apiMethod) + {@initCode(apiMethod.initCode)} + ListenableFuture<{@apiMethod.responseTypeName}> future = {@sampleFutureMethodCall(apiMethod)}; + // Do something + for ({@apiMethod.listMethod.resourceTypeName} element : future.get()) { + // doThingsWith(element); + } +@end + +@snippet unpagedListCallableMethodSampleCode(apiMethod) + {@initCode(apiMethod.initCode)} + while (true) { + {@apiMethod.responseTypeName} response = \ + {@apiMethod.apiVariableName}.{@apiMethod.name}().call(\ + {@sampleMethodCallArgList(apiMethod.initCode.fieldSettings)}); + for ({@apiMethod.listMethod.resourceTypeName} element : \ + response.{@apiMethod.unpagedListCallableMethod.fnGetResourceListCall}()) { + // doThingsWith(element); } - @end + String nextPageToken = response.getNextPageToken(); + if (!Strings.isNullOrEmpty(nextPageToken)) { + request = request.toBuilder().setPageToken(nextPageToken).build(); + } else { + break; + } + } @end -# Helper functions for generateMethodSampleCode() +@snippet syncMethodSampleCode(apiMethod) + {@initCode(apiMethod.initCode)} + @if apiMethod.hasReturnValue + {@apiMethod.responseTypeName} response = {@sampleSyncMethodCall(apiMethod)}; + @else + {@sampleSyncMethodCall(apiMethod)}; + @end +@end -@private getGenericAwareReturnType(docConfig) - @if docConfig.isPagedVariant - PageAccessor<{@docConfig.getGenericAwareReturnType}> +@snippet callableMethodSampleCode(apiMethod) + {@initCode(apiMethod.initCode)} + ListenableFuture<{@apiMethod.callableMethod.genericAwareResponseType}> future = {@sampleFutureMethodCall(apiMethod)}; + // Do something + @if apiMethod.hasReturnValue + {@apiMethod.responseTypeName} response = future.get(); @else - {@docConfig.getGenericAwareReturnType} + future.get(); @end @end -@private getResourcesListCall(resourcesField) - get{@context.lowerUnderscoreToUpperCamel(resourcesField.getSimpleName)}List() +@private sampleFutureMethodCall(apiMethod) + {@apiMethod.apiVariableName}.{@apiMethod.name}().futureCall(\ + {@sampleMethodCallArgList(apiMethod.initCode.fieldSettings)}) +@end + +@private sampleSyncMethodCall(apiMethod) + {@apiMethod.apiVariableName}.{@apiMethod.name}(\ + {@sampleMethodCallArgList(apiMethod.initCode.fieldSettings)}) +@end + +@private sampleMethodCallArgList(fieldSettings) + @join fieldSetting : fieldSettings on ", " + {@fieldSetting.identifier} + @end @end -# Generate argument initialization code for API call @private initCode(initCodeSpec) - @join line : initCodeSpec.getLines() - @switch line.getLineType.toString() + @join line : initCodeSpec.lines + @switch line.lineType.toString @case "StructureInitLine" {@initLineStructure(line)} @case "ListInitLine" @@ -65,125 +90,42 @@ @case "SimpleInitLine" {@initLineSimple(line)} @default - {@unhandledCase()} + $unhandledCase: {@line.lineType.toString}$ @end @end @end -# Generate a Protobuf message argument @private initLineStructure(line) - {@context.typeName(line.getType)} {@formattedIdentifier(line)} = {@context.typeName(line.getType)}.newBuilder() - @join fieldSetting : line.getFieldSettings - @let setCallName = setCallName(fieldSetting.getType, context.lowerUnderscoreToUpperCamel(fieldSetting.getFieldName)) - {@EMPTY} .{@setCallName}({@formattedIdentifier(fieldSetting)}) - @end + {@line.typeName} {@line.identifier} = {@line.typeName}.newBuilder() + @join fieldSetting : line.fieldSettings + {@EMPTY} .{@fieldSetting.fnSetFunctionCallName}({@fieldSetting.identifier}) @end {@EMPTY} .build(); @end -# Generate a List argument @private initLineList(line) - List<{@context.basicTypeNameBoxed(line.getElementType)}> {@formattedIdentifier(line)} = Arrays.asList({@initList(line)}); + List<{@line.elementTypeName}> {@line.identifier} = \ + Arrays.asList({@argList(line.elementIdentifiers)}); @end -# Generate a Map argument @private initLineMap(line) - Map<{@context.basicTypeNameBoxed(line.getKeyType)}, {@context.basicTypeNameBoxed(line.getValueType)}> {@formattedIdentifier(line)} = new HashMap<>(); - @join key : line.getElementIdentifierKeys vertical - @let identifierValue = line.getElementIdentifierValue(key) - {@formattedIdentifier(line)}.put({@context.renderPrimitiveValue(line.getKeyType, key)}, {@context.lowerUnderscoreToLowerCamel(identifierValue)}); - @end - @end -@end - -# Helper method for initLineList() -@private initList(line) - @join identifier : line.getElementIdentifiers on ", " - {@context.lowerUnderscoreToLowerCamel(identifier)} + Map<{@line.keyTypeName}, {@line.valueTypeName}> {@line.identifier} = new HashMap<>(); + @join mapEntry : line.initEntries vertical + {@line.identifier}.put({@mapEntry.key}, {@mapEntry.value}); @end @end -# Generate a simple argument @private initLineSimple(line) - {@context.typeName(line.getType)} {@formattedIdentifier(line)} = {@initValue(line)}; -@end - -# Properly format an identifier for this language -@private formattedIdentifier(lineOrFieldSetting) - @if lineOrFieldSetting.getInitValueConfig.hasFormattingConfig - formatted{@context.lowerUnderscoreToUpperCamel(lineOrFieldSetting.getIdentifier)} - @else - {@context.lowerUnderscoreToLowerCamel(lineOrFieldSetting.getIdentifier)} - @end -@end - -# Value for simple argument -@private initValue(line) - @let metadata = line.getInitValueConfig - @if metadata.hasFormattingConfig() - {@metadata.getApiWrapperName}.{@formatResourceFunctionName(metadata.getCollectionConfig)}({@formatResourceFunctionArgs(metadata.getCollectionConfig)}) - @else - @if metadata.hasInitialValue() - {@context.renderPrimitiveValue(line.getType, metadata.getInitialValue)} - @else - {@context.zeroValue(line.getType)} - @end - @end - @end + {@line.typeName} {@line.identifier} = {@renderInitValue(line.initValue)}; @end -# Format arguments for resource function call in sample -@private formatResourceFunctionArgs(collectionConfig) - @join param : collectionConfig.getNameTemplate.vars() on ", " - "[{@context.lowerUnderscoreToUpperUnderscore(param)}]" - @end -@end - -# Optionally render the return value from the API method call -@private callResultSampleCode(returnType) - @if returnType.isEmpty - @else - {@returnType} response = {@""} - @end -@end - -@private methodFutureCall(docConfig, apiName) - {@apiName}.{@methodCallName(docConfig)}().futureCall({@argList(docConfig.getInitCode.getArgFields)}) -@end - -# Render the API method call itself -@private methodCallSampleCode(docConfig, apiName) - @if docConfig.isUnpagedListCallableVariant - {@apiName}.{@methodCallName(docConfig)}().call({@argList(docConfig.getInitCode.getArgFields)}) - @else - @if docConfig.isCallableVariant - future.get() - @else - {@apiName}.{@methodCallName(docConfig)}({@argList(docConfig.getInitCode.getArgFields)}) - @end - @end -@end - -# Render the name of the method call -@private methodCallName(docConfig) - @if docConfig.isCallableVariant - {@methodCallNameIter(docConfig)}Callable - @else - {@docConfig.getMethodName} - @end -@end - -@private methodCallNameIter(docConfig) - @if docConfig.isPagedVariant - {@docConfig.getMethodName}Paged - @else - {@docConfig.getMethodName} - @end -@end - -# Generate argument list -@private argList(fieldSettings) - @join fieldSetting : fieldSettings on ", " - {@formattedIdentifier(fieldSetting)} +@private renderInitValue(initValue) + @switch initValue.type + @case "SimpleInitValueView" + {@initValue.initialValue} + @case "FormattedInitValueView" + {@initValue.apiWrapperName}.{@initValue.formatFunctionName}({@argList(initValue.formatArgs)}) + @default + $unhandledCase: {@initValue.type}$ @end @end diff --git a/src/main/resources/com/google/api/codegen/java/package-info.snip b/src/main/resources/com/google/api/codegen/java/package-info.snip index a2efe9ec62..4523928682 100644 --- a/src/main/resources/com/google/api/codegen/java/package-info.snip +++ b/src/main/resources/com/google/api/codegen/java/package-info.snip @@ -1,56 +1,50 @@ @extends "java/common.snip" -@extends "java/main.snip" +@extends "java/method_sample.snip" -@snippet generateFilename() - package-info.java -@end - -@snippet generateDocument(fragmentList) +@snippet generate(packageInfo) {@license()} - {@packageJavaDoc(fragmentList)} + /** + * A client to {@packageInfo.serviceTitle}. + * + * The interfaces provided are listed below, along with a usage sample + * + @join xapiClassDoc : packageInfo.serviceDocs + {@serviceShortDoc(xapiClassDoc)} + @end + */ - package {@context.getApiConfig.getPackageName}; + package {@packageInfo.packageName}; @end -@snippet generateFragment(service) - @let firstFlattenedMethod = context.getFirstFlattenedMethod(service), \ - # TODO: support the case where the API has no flattened methods. - firstFlattenedMethodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(firstFlattenedMethod), \ - fields = firstFlattenedMethodConfig.getFlattening().getFlatteningGroups().get(0), \ - fieldNamePatterns = firstFlattenedMethodConfig.getFieldNamePatterns() - {@javaDocLinesFromStr(context.getMultilineHeading(context.getApiWrapperName(service)))} - * - {@javaDocLinesFromStr(serviceDocString(service))} - * - * Sample for {@context.getApiWrapperName(service)}: - *
-     * 
-    @join commentLine : context.java.getJavaDocLines(generateMethodSampleCode(context.newJavaDocConfigBuilder \
-                               .setApiName(context.getApiWrapperName(service)) \
-                               .setMethodName(context.upperCamelToLowerCamel(firstFlattenedMethod.getSimpleName)) \
-                               .setReturnType(context.returnTypeOrEmpty(firstFlattenedMethod.getOutputType)) \
-                               .setFieldInitCode(context, service, firstFlattenedMethod, fields) \
-                               .setFieldParams(context, fields) \
-                               .setPagedVariant({@FALSE}) \
-                               .setCallableVariant({@FALSE}) \
-                               .build))
-      {@commentLine}
-    @end
-    {@EMPTY} * 
-     * 
- * +@private serviceShortDoc(xapiClassDoc) + @let coreSampleCode = syncMethodSampleCode(xapiClassDoc.exampleApiMethod), \ + decoratedSampleCode = decorateSampleCode(xapiClassDoc.exampleApiMethod, coreSampleCode) + {@renderServiceShortDoc(xapiClassDoc, decoratedSampleCode)} @end @end -@private packageJavaDoc(fragmentList) - /** - * A client to {@context.getTitle()}. - * - * The interfaces provided are listed below, along with a usage sample +@private renderServiceShortDoc(xapiClassDoc, exampleMethodSampleCode) + @join commentLine : util.getMultilineHeading(xapiClassDoc.apiClassName) + {@""} * {@commentLine} + @end + # The join above doesn't properly add a newline on the end, so we need to force it + {@""} + {@""} * + * Service Description: {@xapiClassDoc.firstLine} + @if xapiClassDoc.remainingLines + @join commentLine : xapiClassDoc.remainingLines + {@""} * {@commentLine} + @end + @end * - @join fragment : fragmentList - {@fragment} + * Sample for {@xapiClassDoc.apiClassName}: + *
+   * 
+  @join sampleLine : util.getDocLines(exampleMethodSampleCode)
+    {@""} * {@sampleLine}
   @end
-   */
+   * 
+   * 
+ * @end diff --git a/src/main/resources/com/google/api/codegen/java/settings.snip b/src/main/resources/com/google/api/codegen/java/settings.snip index 55838ecabb..3f38d0cf3a 100644 --- a/src/main/resources/com/google/api/codegen/java/settings.snip +++ b/src/main/resources/com/google/api/codegen/java/settings.snip @@ -1,108 +1,70 @@ @extends "java/common.snip" -@snippet generateFilename(service) - {@settingsClassName(service)}.java -@end - -@snippet generateClass(service, body, imports) +@snippet generate(xsettingsClass) {@license()} - package {@context.getApiConfig.getPackageName}; - - @join import : imports + package {@xsettingsClass.packageName}; + + @join import : xsettingsClass.imports import {@import}; @end - {@body} -@end - -@snippet generateBody(service) - {@alwaysImport()} - - {@autoGenClassWarning()} - {@settingsJavaDoc(service)} + {@settingsDoc(xsettingsClass.doc)} @@javax.annotation.Generated("by GAPIC") - public class {@settingsClassName(service)} extends ServiceApiSettings { - - {@constants(service)} - - {@members(service)} - - {@constructors(service)} - - {@descriptors(service)} - - {@innerBuilderClass(service)} + public class {@xsettingsClass.name} extends ServiceApiSettings { + {@constants(xsettingsClass)} + {@members(xsettingsClass)} + {@constructors(xsettingsClass)} + {@descriptors(xsettingsClass)} + {@innerBuilderClass(xsettingsClass)} } @end -@private alwaysImport() fill - {@context.addImport("com.google.api.gax.core.ConnectionSettings")} - {@context.addImport("com.google.api.gax.core.RetrySettings")} - {@context.addImport("com.google.api.gax.grpc.ApiCallSettings")} - {@context.addImport("com.google.api.gax.grpc.SimpleCallSettings")} - {@context.addImport("com.google.api.gax.grpc.ServiceApiSettings")} - {@context.addImport("com.google.auth.Credentials")} - {@context.addImport("com.google.common.collect.ImmutableList")} - {@context.addImport("com.google.common.collect.ImmutableMap")} - {@context.addImport("com.google.common.collect.ImmutableSet")} - {@context.addImport("com.google.common.collect.Lists")} - {@context.addImport("com.google.common.collect.Sets")} - {@context.addImport("io.grpc.ManagedChannel")} - {@context.addImport("io.grpc.Status")} - {@context.addImport("org.joda.time.Duration")} - {@context.addImport("java.io.IOException")} - {@context.addImport("java.util.List")} - {@context.addImport("java.util.concurrent.ScheduledExecutorService")} -@end - -@private settingsJavaDoc(service) - @let settingsVariable = context.upperCamelToLowerCamel(settingsClassName(service)), \ - firstFlattenedMethod = context.getFirstFlattenedMethod(service) - /** - * Settings class to configure an instance of {@@link {@context.getApiWrapperName(service)}}. - * - *

The default instance has everything set to sensible defaults: - * - *

    - *
  • The default service address ({@context.getServiceConfig.getServiceAddress(service)}) and default port ({@context.getServiceConfig.getServicePort()}) - * are used. - *
  • Credentials are acquired automatically through Application Default Credentials. - *
  • Retries are configured for idempotent methods but not for non-idempotent methods. - *
- * - *

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 {@firstFlattenedMethod.getSimpleName} to 30 seconds: - * - *

-     * 
-     * {@settingsClassName(service)}.Builder {@settingsVariable}Builder =
-     *     {@settingsClassName(service)}.defaultBuilder();
-     * {@settingsVariable}Builder.{@firstFlattenedMethod.getSimpleName}Settings().getRetrySettingsBuilder()
-     *     .setTotalTimeout(Duration.standardSeconds(30));
-     * {@settingsClassName(service)} {@settingsVariable} = {@settingsVariable}Builder.build();
-     * 
-     * 
- */ - @end +@private settingsDoc(doc) + // AUTO-GENERATED DOCUMENTATION AND CLASS + /** + * Settings class to configure an instance of {@@link {@doc.apiClassName}}. + * + *

The default instance has everything set to sensible defaults: + * + *

    + *
  • The default service address ({@doc.serviceAddress}) and default port ({@doc.servicePort}) + * are used. + *
  • Credentials are acquired automatically through Application Default Credentials. + *
  • Retries are configured for idempotent methods but not for non-idempotent methods. + *
+ * + *

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 {@doc.exampleApiMethodName} to 30 seconds: + * + *

+   * 
+   * {@doc.settingsClassName}.Builder {@doc.settingsBuilderVarName} =
+   *     {@doc.settingsClassName}.defaultBuilder();
+   * {@doc.settingsBuilderVarName}.{@doc.exampleApiMethodSettingsGetter}().getRetrySettingsBuilder()
+   *     .setTotalTimeout(Duration.standardSeconds(30));
+   * {@doc.settingsClassName} {@doc.settingsVarName} = {@doc.settingsBuilderVarName}.build();
+   * 
+   * 
+ */ @end -@private constants(service) +@private constants(xsettingsClass) /** * The default address of the service. */ - public static final String DEFAULT_SERVICE_ADDRESS = "{@context.getServiceConfig.getServiceAddress(service)}"; + public static final String DEFAULT_SERVICE_ADDRESS = "{@xsettingsClass.serviceAddress}"; /** * The default port of the service. */ - public static final int DEFAULT_SERVICE_PORT = {@context.getServiceConfig.getServicePort()}; + public static final int DEFAULT_SERVICE_PORT = {@xsettingsClass.servicePort}; /** * The default scopes of the service. */ public static final ImmutableList DEFAULT_SERVICE_SCOPES = ImmutableList.builder() - @join scope : context.getServiceConfig.getAuthScopes(service) + @join scope : {@xsettingsClass.authScopes} .add("{@scope}") @end .build(); @@ -116,310 +78,356 @@ .setPort(DEFAULT_SERVICE_PORT) .provideCredentialsWith(DEFAULT_SERVICE_SCOPES) .build(); + {@""} @end -@private members(service) - {@methodMembers(service)} - - {@methodGetters(service)} - - @let className = settingsClassName(service) - /** - * Returns a builder for this class with recommended defaults. - */ - public static Builder defaultBuilder() { - return Builder.createDefault(); - } +@private members(xsettingsClass) + {@methodMembers(xsettingsClass)} + {@methodGetters(xsettingsClass)} + /** + * Returns a builder for this class with recommended defaults. + */ + public static Builder defaultBuilder() { + return Builder.createDefault(); + } - /** - * Returns a new builder for this class. - */ - public static Builder newBuilder() { - return new Builder(); - } + /** + * Returns a new builder for this class. + */ + public static Builder newBuilder() { + return new Builder(); + } - /** - * Returns a builder containing all the values of this settings class. - */ - public Builder toBuilder() { - return new Builder(this); - } - @end + /** + * Returns a builder containing all the values of this settings class. + */ + public Builder toBuilder() { + return new Builder(this); + } + {@""} @end -@private methodMembers(service) - @join method : service.getMethods - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - inTypeName = context.typeName(method.getInputType), \ - outTypeName = context.typeName(method.getOutputType), \ - isPageStreaming = methodConfig.isPageStreaming, \ - isBundling = methodConfig.isBundling - @if {@isPageStreaming} - @let pageStreaming = methodConfig.getPageStreaming(), \ - resourceTypeName = context.basicTypeNameBoxed(pageStreaming.getResourcesField().getType()), \ - dummy = context.addImport("com.google.api.gax.grpc.PageStreamingCallSettings") - private final PageStreamingCallSettings<{@inTypeName}, {@outTypeName}, {@resourceTypeName}> - {@methodName}Settings; - - @end - @else - @if {@isBundling} - @let bundling = methodConfig.getBundling(), \ - dummy = context.addImport("com.google.api.gax.grpc.BundlingCallSettings") - private final BundlingCallSettings<{@inTypeName}, {@outTypeName}> {@methodName}Settings; - @end - @else - private final SimpleCallSettings<{@inTypeName}, {@outTypeName}> {@methodName}Settings; - @end - @end +@private methodMembers(xsettingsClass) + @join settings : xsettingsClass.callSettings + @switch settings.type.toString + @case "SimpleApiCallable" + private final SimpleCallSettings<{@settings.requestTypeName}, \ + {@settings.responseTypeName}> {@settings.memberName}; + @case "PagedApiCallable" + private final PageStreamingCallSettings<{@settings.requestTypeName}, \ + {@settings.responseTypeName}, {@settings.resourceTypeName}> {@settings.memberName}; + @case "BundlingApiCallable" + private final BundlingCallSettings<{@settings.requestTypeName}, \ + {@settings.responseTypeName}> {@settings.memberName}; + @default + $unhandledCase: {@settings.type.toString}$ @end @end + {@BREAK} @end -@private methodGetters(service) - @join method : service.getMethods - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - inTypeName = context.typeName(method.getInputType), \ - outTypeName = context.typeName(method.getOutputType), \ - isPageStreaming = methodConfig.isPageStreaming, \ - isBundling = methodConfig.isBundling - /** - * Returns the object with the settings used for calls to {@methodName}. - */ - @if {@isPageStreaming} - @let pageStreaming = methodConfig.getPageStreaming(), \ - resourceTypeName = context.basicTypeNameBoxed(pageStreaming.getResourcesField().getType()), \ - dummy = context.addImport("com.google.api.gax.grpc.PageStreamingCallSettings") - public PageStreamingCallSettings<{@inTypeName}, {@outTypeName}, {@resourceTypeName}> - {@methodName}Settings() { - return {@methodName}Settings; - } - - @end - @else - @if {@isBundling} - @let bundling = methodConfig.getBundling(), \ - dummy = context.addImport("com.google.api.gax.grpc.BundlingCallSettings") - public BundlingCallSettings<{@inTypeName}, {@outTypeName}> {@methodName}Settings() { - return {@methodName}Settings; - } - - @end - @else - public SimpleCallSettings<{@inTypeName}, {@outTypeName}> {@methodName}Settings() { - return {@methodName}Settings; - } - - @end - @end +@private methodGetters(xsettingsClass) + @join settings : xsettingsClass.callSettings + /** + * Returns the object with the settings used for calls to {@settings.methodName}. + */ + @switch settings.type.toString + @case "SimpleApiCallable" + public SimpleCallSettings<{@settings.requestTypeName}, \ + {@settings.responseTypeName}> {@settings.fnGetterName}() { + return {@settings.memberName}; + } + @case "PagedApiCallable" + public PageStreamingCallSettings<{@settings.requestTypeName}, \ + {@settings.responseTypeName}, {@settings.resourceTypeName}> {@settings.fnGetterName}() { + return {@settings.memberName}; + } + @case "BundlingApiCallable" + public BundlingCallSettings<{@settings.requestTypeName}, \ + {@settings.responseTypeName}> {@settings.fnGetterName}() { + return {@settings.memberName}; + } + @default + $unhandledCase: {@settings.type.toString}$ @end + {@""} @end @end -@private constructors(service) - @let className = settingsClassName(service) - private {@className}(Builder settingsBuilder) throws IOException { - super(settingsBuilder.getChannelProvider(), - settingsBuilder.getExecutorProvider(), - settingsBuilder.getGeneratorName(), - settingsBuilder.getGeneratorVersion(), - settingsBuilder.getClientLibName(), - settingsBuilder.getClientLibVersion()); - - @join method : service.getMethods - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName) - {@methodName}Settings = settingsBuilder.{@methodName}Settings().build(); - @end - @end - } - @end +@private constructors(xsettingsClass) + private {@xsettingsClass.name}(Builder settingsBuilder) throws IOException { + super(settingsBuilder.getChannelProvider(), + settingsBuilder.getExecutorProvider(), + settingsBuilder.getGeneratorName(), + settingsBuilder.getGeneratorVersion(), + settingsBuilder.getClientLibName(), + settingsBuilder.getClientLibVersion()); + + @join settings : xsettingsClass.callSettings + {@settings.memberName} = settingsBuilder.{@settings.fnGetterName}().build(); + @end + } + {@""} @end -@private descriptors(service) - {@pageStreamingDescriptors(service)} - {@bundlingDescriptors(service)} +@private descriptors(xsettingsClass) + {@pageStreamingDescriptors(xsettingsClass)} + {@bundlingDescriptors(xsettingsClass)} @end -@private pageStreamingDescriptors(service) - @let interfaceConfig = context.getApiConfig.getInterfaceConfig(service), \ - dummy = context.addImport("com.google.api.gax.grpc.PageStreamingDescriptor") - @join method : context.messages.filterPageStreamingMethods(interfaceConfig, service.getMethods) - @let methodConstant = context.upperCamelToUpperUnderscore(method.getSimpleName), \ - inTypeName = context.typeName(method.getInputType), \ - outTypeName = context.typeName(method.getOutputType), \ - pageStreaming = interfaceConfig.getMethodConfig(method).getPageStreaming(), \ - resourceTypeName = context.basicTypeNameBoxed(pageStreaming.getResourcesField().getType()), \ - tokenTypeName = context.typeName(pageStreaming.getResponseTokenField.getType) - private static PageStreamingDescriptor<{@inTypeName}, {@outTypeName}, {@resourceTypeName}> {@methodConstant}_PAGE_STR_DESC = - new PageStreamingDescriptor<{@inTypeName}, {@outTypeName}, {@resourceTypeName}>() { - @@Override - public Object emptyToken() { - return {@context.defaultTokenValue(pageStreaming.getRequestTokenField())}; - } - @@Override - public {@inTypeName} injectToken( - {@inTypeName} payload, Object token) { - return {@inTypeName} - .newBuilder(payload) - .{@setCallName(pageStreaming.getRequestTokenField())}(({@tokenTypeName}) token) - .build(); - } - @@Override - public Object extractNextToken({@outTypeName} payload) { - return payload.{@getCallName(pageStreaming.getResponseTokenField())}(); - } - @@Override - public Iterable<{@resourceTypeName}> extractResources({@outTypeName} payload) { - return payload.{@getCallName(pageStreaming.getResourcesField())}(); - } - }; - - @end - @end +@private pageStreamingDescriptors(xsettingsClass) + @join desc : xsettingsClass.pageStreamingDescriptors + private static PageStreamingDescriptor<{@desc.requestTypeName}, {@desc.responseTypeName}, {@desc.resourceTypeName}> {@desc.name} = + new PageStreamingDescriptor<{@desc.requestTypeName}, {@desc.responseTypeName}, {@desc.resourceTypeName}>() { + @@Override + public Object emptyToken() { + return {@desc.defaultTokenValue}; + } + @@Override + public {@desc.requestTypeName} injectToken({@desc.requestTypeName} payload, Object token) { + return {@desc.requestTypeName} + .newBuilder(payload) + .{@desc.fnSetRequestToken}(({@desc.tokenTypeName}) token) + .build(); + } + @@Override + public Object extractNextToken({@desc.responseTypeName} payload) { + return payload.{@desc.fnGetResponseToken}(); + } + @@Override + public Iterable<{@desc.resourceTypeName}> extractResources({@desc.responseTypeName} payload) { + return payload.{@desc.fnGetResourcesField}(); + } + }; + {@""} @end @end -@private bundlingDescriptors(service) - @let interfaceConfig = context.getApiConfig.getInterfaceConfig(service) - @join method : context.messages.filterBundlingMethods(interfaceConfig, service.getMethods) - @let methodConstant = context.upperCamelToUpperUnderscore(method.getSimpleName), \ - inTypeName = context.typeName(method.getInputType), \ - outTypeName = context.typeName(method.getOutputType), \ - bundling = interfaceConfig.getMethodConfig(method).getBundling(), \ - dummy = context.addImport("com.google.api.gax.grpc.BundlingDescriptor"), \ - dummy2 = context.addImport("java.util.Collection"), \ - dummy3 = context.addImport("com.google.api.gax.grpc.RequestIssuer"), \ - dummy4 = context.addImport("java.util.ArrayList") - private static BundlingDescriptor<{@inTypeName}, {@outTypeName}> {@methodConstant}_BUNDLING_DESC = - new BundlingDescriptor<{@inTypeName}, {@outTypeName}>() { - @@Override - public String getBundlePartitionKey({@inTypeName} request) { - return {@partitionKeyCode(bundling)}; - } +@private bundlingDescriptors(xsettingsClass) + @join desc : xsettingsClass.bundlingDescriptors + private static BundlingDescriptor<{@desc.requestTypeName}, {@desc.responseTypeName}> {@desc.name} = + new BundlingDescriptor<{@desc.requestTypeName}, {@desc.responseTypeName}>() { + @@Override + public String getBundlePartitionKey({@desc.requestTypeName} request) { + return {@partitionKeyCode(desc)}; + } - @@Override - public {@inTypeName} mergeRequests(Collection<{@inTypeName}> requests) { - {@inTypeName} firstRequest = requests.iterator().next(); - - {@context.typeName(bundling.getBundledField.getType)} elements = new ArrayList<>(); - for ({@inTypeName} request : requests) { - elements.addAll(request.{@getCallName(bundling.getBundledField)}()); - } - - {@inTypeName} bundleRequest = - {@inTypeName}.newBuilder() - {@setDescriminatorFields(bundling)} - .{@setCallName(bundling.getBundledField)}(elements) - .build(); - return bundleRequest; - } + @@Override + public {@desc.requestTypeName} mergeRequests(Collection<{@desc.requestTypeName}> requests) { + {@desc.requestTypeName} firstRequest = requests.iterator().next(); - @@Override - public void splitResponse( - {@outTypeName} bundleResponse, - Collection> bundle) { - # TODO(garrettjones) support case of no subresponse_field (e.g. Logging) - int bundleMessageIndex = 0; - for (RequestIssuer<{@inTypeName}, {@outTypeName}> responder : bundle) { - {@context.typeName(bundling.getSubresponseField.getType)} subresponseElements = new ArrayList<>(); - int subresponseCount = responder.getRequest().{@getCountCallName(bundling.getBundledField)}(); - for (int i = 0; i < subresponseCount; i++) { - subresponseElements.add(bundleResponse.{@getIndexCallName(bundling.getSubresponseField)}(bundleMessageIndex)); - bundleMessageIndex += 1; - } - {@outTypeName} response = - {@outTypeName}.newBuilder().{@setCallName(bundling.getSubresponseField)}(subresponseElements).build(); - responder.setResponse(response); - } - } + {@desc.bundledFieldTypeName} elements = new ArrayList<>(); + for ({@desc.requestTypeName} request : requests) { + elements.addAll(request.{@desc.fnGetBundledField}()); + } - @@Override - public void splitException( - Throwable throwable, - Collection> bundle) { - for (RequestIssuer<{@inTypeName}, {@outTypeName}> responder : bundle) { - responder.setException(throwable); - } - } + {@desc.requestTypeName} bundleRequest = + {@desc.requestTypeName}.newBuilder() + {@fieldCopyCalls(desc.discriminatorFieldCopies)} + .{@desc.fnSetBundledField}(elements) + .build(); + return bundleRequest; + } - @@Override - public long countElements({@inTypeName} request) { - return request.{@getCountCallName(bundling.getBundledField)}(); + @@Override + public void splitResponse( + {@desc.responseTypeName} bundleResponse, + Collection> bundle) { + # TODO(garrettjones) support case of no subresponse_field (e.g. Logging) + int bundleMessageIndex = 0; + for (RequestIssuer<{@desc.requestTypeName}, {@desc.responseTypeName}> responder : bundle) { + {@desc.subresponseTypeName} subresponseElements = new ArrayList<>(); + int subresponseCount = responder.getRequest().{@desc.fnGetBundledFieldCount}(); + for (int i = 0; i < subresponseCount; i++) { + subresponseElements.add(bundleResponse.{@desc.fnGetSubresponseByIndex}(bundleMessageIndex)); + bundleMessageIndex += 1; } + {@desc.responseTypeName} response = + {@desc.responseTypeName}.newBuilder().{@desc.fnSetSubresponse}(subresponseElements).build(); + responder.setResponse(response); + } + } - @@Override - public long countBytes({@inTypeName} request) { - return request.getSerializedSize(); - } - }; + @@Override + public void splitException( + Throwable throwable, + Collection> bundle) { + for (RequestIssuer<{@desc.requestTypeName}, {@desc.responseTypeName}> responder : bundle) { + responder.setException(throwable); + } + } - @end - @end + @@Override + public long countElements({@desc.requestTypeName} request) { + return request.{@desc.fnGetBundledFieldCount}(); + } + + @@Override + public long countBytes({@desc.requestTypeName} request) { + return request.getSerializedSize(); + } + }; + {@""} @end @end -@private partitionKeyCode(bundling) - {@context.partitionKeyCode(bundling.getDiscriminatorFields)} +@private partitionKeyCode(bundlingDesc) + @join partitionKey : bundlingDesc.partitionKeys on " + " + request.{@partitionKey.fnGetCallName}() + {@partitionKey.separatorLiteral} + @end @end -@private setDescriminatorFields(bundling) - @join fieldSelector : bundling.getDiscriminatorFields - # Note: This only supports field selectors with a single field. - @let field = fieldSelector.getLastField - .{@setCallName(field)}(firstRequest.{@getCallName(field)}()) - @end +@private fieldCopyCalls(fieldCopies) + @join fieldCopy : fieldCopies + .{@fieldCopy.fnSetFunctionCallName}(firstRequest.{@fieldCopy.fnGetFunctionCallName}()) @end @end -@private innerBuilderClass(service) +@private innerBuilderClass(xsettingsClass) /** - * Builder for {@settingsClassName(service)}. + * Builder for {@xsettingsClass.name}. */ public static class Builder extends ServiceApiSettings.Builder { private final ImmutableList methodSettingsBuilders; - {@builderMembers(service)} + {@builderMembers(xsettingsClass)} - {@builderConstants(service)} + {@builderConstants(xsettingsClass)} - {@builderConstructors(service)} + {@builderConstructors(xsettingsClass)} - {@builderMethods(service)} + {@builderMethods(xsettingsClass)} } @end -@private builderMembers(service) - @join method : service.getMethods - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - inTypeName = context.typeName(method.getInputType), \ - outTypeName = context.typeName(method.getOutputType), \ - isPageStreaming = methodConfig.isPageStreaming, \ - isBundling = methodConfig.isBundling - @if {@isPageStreaming} - @let pageStreaming = methodConfig.getPageStreaming(), \ - resourceTypeName = context.basicTypeNameBoxed(pageStreaming.getResourcesField().getType()), \ - dummy = context.addImport("com.google.api.gax.grpc.PageStreamingCallSettings") - private PageStreamingCallSettings.Builder<{@inTypeName}, {@outTypeName}, {@resourceTypeName}> - {@methodName}Settings; - @end - @else - @if {@isBundling} - @let bundling = methodConfig.getBundling(), \ - dummy = context.addImport("com.google.api.gax.grpc.BundlingCallSettings") - private BundlingCallSettings.Builder<{@inTypeName}, {@outTypeName}> {@methodName}Settings; - @end - @else - private SimpleCallSettings.Builder<{@inTypeName}, {@outTypeName}> {@methodName}Settings; +@private builderMembers(xsettingsClass) + @join settings : xsettingsClass.callSettings + @switch settings.type.toString + @case "SimpleApiCallable" + private SimpleCallSettings.Builder<{@settings.requestTypeName}, \ + {@settings.responseTypeName}> {@settings.memberName}; + @case "PagedApiCallable" + private PageStreamingCallSettings.Builder<{@settings.requestTypeName}, \ + {@settings.responseTypeName}, {@settings.resourceTypeName}> {@settings.memberName}; + @case "BundlingApiCallable" + private BundlingCallSettings.Builder<{@settings.requestTypeName}, \ + {@settings.responseTypeName}> {@settings.memberName}; + @default + $unhandledCase: {@settings.type.toString}$ + @end + @end +@end + +@private builderConstants(xsettingsClass) + private static final ImmutableMap> RETRYABLE_CODE_DEFINITIONS; + + static { + ImmutableMap.Builder> definitions = ImmutableMap.builder(); + @join retryCodesDef : xsettingsClass.retryCodesDefinitions + definitions.put( + "{@retryCodesDef.key}", + Sets.immutableEnumSet(Lists.newArrayList({@statusCodes(retryCodesDef.codes)}))); + @end + RETRYABLE_CODE_DEFINITIONS = definitions.build(); + } + + private static final ImmutableMap RETRY_PARAM_DEFINITIONS; + + static { + ImmutableMap.Builder definitions = ImmutableMap.builder(); + RetrySettings.Builder settingsBuilder = null; + @join retryParamsDef : xsettingsClass.retryParamsDefinitions + settingsBuilder = RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.millis({@retryParamsDef.initialRetryDelay.getMillis}L)) + .setRetryDelayMultiplier({@retryParamsDef.retryDelayMultiplier}) + .setMaxRetryDelay(Duration.millis({@retryParamsDef.maxRetryDelay.getMillis}L)) + .setInitialRpcTimeout(Duration.millis({@retryParamsDef.initialRpcTimeout.getMillis}L)) + .setRpcTimeoutMultiplier({@retryParamsDef.rpcTimeoutMultiplier}) + .setMaxRpcTimeout(Duration.millis({@retryParamsDef.maxRpcTimeout.getMillis}L)) + .setTotalTimeout(Duration.millis({@retryParamsDef.totalTimeout.getMillis}L)); + definitions.put("{@retryParamsDef.key}", settingsBuilder); + @end + RETRY_PARAM_DEFINITIONS = definitions.build(); + } +@end + +@private statusCodes(codes) + @join code : codes on ", " + Status.Code.{@code} + @end +@end + +@private builderConstructors(xsettingsClass) + private Builder() { + super(DEFAULT_CONNECTION_SETTINGS); + + @join settings : xsettingsClass.callSettings + @switch settings.type.toString + @case "SimpleApiCallable" + {@settings.memberName} = SimpleCallSettings.newBuilder({@settings.grpcTypeName}.{@settings.grpcMethodConstant}); + @case "PagedApiCallable" + {@settings.memberName} = PageStreamingCallSettings.newBuilder( + {@settings.grpcTypeName}.{@settings.grpcMethodConstant}, + {@settings.pageStreamingDescriptorName}); + @case "BundlingApiCallable" + {@settings.memberName} = BundlingCallSettings.newBuilder( + {@settings.grpcTypeName}.{@settings.grpcMethodConstant}, + {@settings.bundlingDescriptorName}) + .setBundlingSettingsBuilder(BundlingSettings.newBuilder()); + @default + $unhandledCase: {@settings.type.toString}$ + @end + {@BREAK} + @end + methodSettingsBuilders = ImmutableList.of( + @join settings : xsettingsClass.callSettings vertical on ",".add(BREAK) + {@settings.memberName} @end + ); + } + + private static Builder createDefault() { + Builder builder = new Builder(); + @join settings : xsettingsClass.callSettings + {@""} + @switch settings.type.toString + @case "SimpleApiCallable" + @case "PagedApiCallable" + @case "BundlingApiCallable" + builder.{@settings.fnGetterName}().getBundlingSettingsBuilder() + .setElementCountThreshold({@settings.bundlingConfig.elementCountThreshold}) + .setElementCountLimit({@settings.bundlingConfig.elementCountLimit}) + .setRequestByteThreshold({@settings.bundlingConfig.requestByteThreshold}) + .setRequestByteLimit({@settings.bundlingConfig.requestByteLimit}) + .setDelayThreshold(Duration.millis({@settings.bundlingConfig.delayThresholdMillis})) + .setBlockingCallCountThreshold(1); + @default + $unhandledCase: {@settings.type.toString}$ @end + builder.{@settings.fnGetterName}() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("{@settings.retryCodesName}")) + .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("{@settings.retryParamsName}")); @end - @end + + return builder; + } + + private Builder({@xsettingsClass.name} settings) { + super(settings); + + @join settings : xsettingsClass.callSettings + {@settings.memberName} = settings.{@settings.memberName}.toBuilder(); + @end + + methodSettingsBuilders = ImmutableList.of( + @join settings : xsettingsClass.callSettings vertical on ",".add(BREAK) + {@settings.memberName} + @end + ); + } @end -@private builderMethods(service) +@private builderMethods(xsettingsClass) @@Override protected ConnectionSettings getDefaultConnectionSettings() { return DEFAULT_CONNECTION_SETTINGS; @@ -470,210 +478,33 @@ return this; } - @join method : service.getMethods - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - inTypeName = context.typeName(method.getInputType), \ - outTypeName = context.typeName(method.getOutputType), \ - isPageStreaming = methodConfig.isPageStreaming, \ - isBundling = methodConfig.isBundling - /** - * Returns the builder for the settings used for calls to {@methodName}. - */ - @if {@isPageStreaming} - @let pageStreaming = methodConfig.getPageStreaming(), \ - resourceTypeName = context.basicTypeNameBoxed(pageStreaming.getResourcesField().getType()), \ - dummy = context.addImport("com.google.api.gax.grpc.PageStreamingCallSettings") - public PageStreamingCallSettings.Builder<{@inTypeName}, {@outTypeName}, {@resourceTypeName}> - {@methodName}Settings() { - return {@methodName}Settings; - } - - @end - @else - @if {@isBundling} - @let bundling = methodConfig.getBundling(), \ - dummy = context.addImport("com.google.api.gax.grpc.BundlingCallSettings") - public BundlingCallSettings.Builder<{@inTypeName}, {@outTypeName}> {@methodName}Settings() { - return {@methodName}Settings; - } - - @end - @else - public SimpleCallSettings.Builder<{@inTypeName}, {@outTypeName}> {@methodName}Settings() { - return {@methodName}Settings; - } - - @end - @end + @join settings : xsettingsClass.callSettings + /** + * Returns the builder for the settings used for calls to {@settings.methodName}. + */ + @switch settings.type.toString + @case "SimpleApiCallable" + public SimpleCallSettings.Builder<{@settings.requestTypeName}, \ + {@settings.responseTypeName}> {@settings.fnGetterName}() { + return {@settings.memberName}; + } + @case "PagedApiCallable" + public PageStreamingCallSettings.Builder<{@settings.requestTypeName}, \ + {@settings.responseTypeName}, {@settings.resourceTypeName}> {@settings.fnGetterName}() { + return {@settings.memberName}; + } + @case "BundlingApiCallable" + public BundlingCallSettings.Builder<{@settings.requestTypeName}, \ + {@settings.responseTypeName}> {@settings.fnGetterName}() { + return {@settings.memberName}; + } + @default + $unhandledCase: {@settings.type.toString}$ @end + {@""} @end @@Override - public {@settingsClassName(service)} build() throws IOException { - return new {@settingsClassName(service)}(this); + public {@xsettingsClass.name} build() throws IOException { + return new {@xsettingsClass.name}(this); } @end - -@private builderConstants(service) - @let interfaceConfig = context.getApiConfig.getInterfaceConfig(service) - private static final ImmutableMap> RETRYABLE_CODE_DEFINITIONS; - - static { - ImmutableMap.Builder> definitions = ImmutableMap.builder(); - @join retryDef : context.entrySet(interfaceConfig.getRetryCodesDefinition) - definitions.put( - "{@retryDef.getKey}", - Sets.immutableEnumSet(Lists.newArrayList({@statusCodes(retryDef.getValue)}))); - @end - RETRYABLE_CODE_DEFINITIONS = definitions.build(); - } - - private static final ImmutableMap RETRY_PARAM_DEFINITIONS; - - static { - ImmutableMap.Builder definitions = ImmutableMap.builder(); - RetrySettings.Builder settingsBuilder = null; - @join retryDef : context.entrySet(interfaceConfig.getRetrySettingsDefinition) - settingsBuilder = RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.millis({@retryDef.getValue.getInitialRetryDelay.getMillis}L)) - .setRetryDelayMultiplier({@retryDef.getValue.getRetryDelayMultiplier}) - .setMaxRetryDelay(Duration.millis({@retryDef.getValue.getMaxRetryDelay.getMillis}L)) - .setInitialRpcTimeout(Duration.millis({@retryDef.getValue.getInitialRpcTimeout.getMillis}L)) - .setRpcTimeoutMultiplier({@retryDef.getValue.getRpcTimeoutMultiplier}) - .setMaxRpcTimeout(Duration.millis({@retryDef.getValue.getMaxRpcTimeout.getMillis}L)) - .setTotalTimeout(Duration.millis({@retryDef.getValue.getTotalTimeout.getMillis}L)); - definitions.put("{@retryDef.getKey}", settingsBuilder); - @end - RETRY_PARAM_DEFINITIONS = definitions.build(); - } - @end -@end - -@private statusCodes(codes) - @join code : codes on ", " - Status.Code.{@code} - @end -@end - -@private builderConstructors(service) - private Builder() { - super(DEFAULT_CONNECTION_SETTINGS); - - @let serviceName = service.getSimpleName, \ - grpcName = context.getGrpcName(service) - @join method : service.getMethods - @let methodConstant = context.upperCamelToUpperUnderscore(method.getSimpleName), \ - methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - retryCodesName = methodConfig.getRetryCodesConfigName, \ - RetrySettingsName = methodConfig.getRetrySettingsConfigName, \ - isPageStreaming = methodConfig.isPageStreaming, \ - isBundling = methodConfig.isBundling - @if {@isPageStreaming} - @let dummy = {@context.addImport("com.google.api.gax.grpc.PageStreamingCallSettings")} - {@methodName}Settings = PageStreamingCallSettings.newBuilder( - {@grpcName}.METHOD_{@methodConstant}, - {@methodConstant}_PAGE_STR_DESC); - - @end - @else - @if {@isBundling} - @let bundlingConfig = methodConfig.getBundling, \ - dummy = {@context.addImport("com.google.api.gax.grpc.BundlingSettings")} - {@methodName}Settings = BundlingCallSettings.newBuilder( - {@grpcName}.METHOD_{@methodConstant}, - {@methodConstant}_BUNDLING_DESC) - .setBundlingSettingsBuilder(BundlingSettings.newBuilder()); - - @end - @else - {@methodName}Settings = SimpleCallSettings.newBuilder({@grpcName}.METHOD_{@methodConstant}); - - @end - @end - @end - @end - @end - methodSettingsBuilders = ImmutableList.of( - {@settingsList(service)} - ); - } - - private static Builder createDefault() { - Builder builder = new Builder(); - @let serviceName = service.getSimpleName, \ - grpcName = context.getGrpcName(service) - @join method : service.getMethods - @let methodConstant = context.upperCamelToUpperUnderscore(method.getSimpleName), \ - methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - retryCodesName = methodConfig.getRetryCodesConfigName, \ - RetrySettingsName = methodConfig.getRetrySettingsConfigName, \ - isPageStreaming = methodConfig.isPageStreaming, \ - isBundling = methodConfig.isBundling - @if {@isPageStreaming} - @let dummy = {@context.addImport("com.google.api.gax.grpc.PageStreamingCallSettings")} - builder.{@methodName}Settings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("{@retryCodesName}")) - .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("{@RetrySettingsName}")); - - @end - @else - @if {@isBundling} - @let bundlingConfig = methodConfig.getBundling, \ - dummy = {@context.addImport("com.google.api.gax.grpc.BundlingSettings")} - builder.{@methodName}Settings().getBundlingSettingsBuilder() - .setElementCountThreshold({@bundlingConfig.getElementCountThreshold}) - .setElementCountLimit({@bundlingConfig.getElementCountLimit}) - .setRequestByteThreshold({@bundlingConfig.getRequestByteThreshold}) - .setRequestByteLimit({@bundlingConfig.getRequestByteLimit}) - .setDelayThreshold(Duration.millis({@bundlingConfig.getDelayThresholdMillis})) - .setBlockingCallCountThreshold(1); - builder.{@methodName}Settings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("{@retryCodesName}")) - .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("{@RetrySettingsName}")); - - @end - @else - builder.{@methodName}Settings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("{@retryCodesName}")) - .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("{@RetrySettingsName}")); - - @end - @end - @end - @end - @end - return builder; - } - - private Builder({@settingsClassName(service)} settings) { - super(settings); - - @join method : service.getMethods - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - isPageStreaming = methodConfig.isPageStreaming - {@methodName}Settings = settings.{@methodName}Settings.toBuilder(); - @end - @end - - methodSettingsBuilders = ImmutableList.of( - {@settingsList(service)} - ); - } -@end - -@private settingsList(service) - @join method : service.getMethods vertical on ",".add(BREAK) - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - isPageStreaming = methodConfig.isPageStreaming - {@methodName}Settings - @end - @end -@end - -@snippet generateMethodSampleCode(sampleConfig) -# not used -@end diff --git a/src/main/resources/com/google/api/codegen/php/main.snip b/src/main/resources/com/google/api/codegen/php/main.snip index 902c6a55bf..304f960b79 100644 --- a/src/main/resources/com/google/api/codegen/php/main.snip +++ b/src/main/resources/com/google/api/codegen/php/main.snip @@ -1,23 +1,30 @@ -@extends "common.snip" +@extends "php/mvvm_common.snip" @extends "php/method_sample.snip" -@snippet generateFilename(service) - {@context.getApiWrapperName(service)}.php -@end - -@snippet generateClass(service, body, imports) +@snippet generate(xapiClass) '{@pageStreaming.getRequestTokenField.getSimpleName}', - 'responsePageTokenField' => '{@pageStreaming.getResponseTokenField.getSimpleName}', - 'resourceField' => '{@pageStreaming.getResourcesField.getSimpleName}', - ]); - @end - @end - - $pageStreamingDescriptors = [ - @join method : context.messages.filterPageStreamingMethods(interfaceConfig, service.getMethods) - @let methodName = context.upperCamelToLowerCamel(method.getSimpleName) - '{@methodName}' => ${@methodName}PageStreamingDescriptor, - @end - @end - ]; - - return $pageStreamingDescriptors; - } +@private staticFunctions(xapiClass) + @join function : xapiClass.formatResourceFunctions + {@formatResourceFunction(function)} @end -@end - -@private resourceFunctions(service) - @join collectionConfig : context.getApiConfig.getInterfaceConfig(service).getCollectionConfigs() - {@formatResourceFunction(collectionConfig)} + {@""} + @join function : xapiClass.parseResourceFunctions + {@parseResourceFunction(function)} @end - - @join collectionConfig : context.getApiConfig.getInterfaceConfig(service).getCollectionConfigs() - {@parseResourceFunction(collectionConfig)} - @end - - @join collectionConfig : context.getApiConfig.getInterfaceConfig(service).getCollectionConfigs() - {@pathTemplateFunction(collectionConfig)} + {@""} + @join function : xapiClass.pathTemplateGetterFunctions + {@pathTemplateGetterFunction(function)} @end + {@pageStreamingDescriptorFunction(xapiClass)} @end -@private formatResourceFunction(collectionConfig) +@private formatResourceFunction(function) /** * Formats a string containing the fully-qualified path to represent - * a {@collectionConfig.getEntityName} resource. + * a {@function.entityName} resource. */ - public static function {@formatResourceFunctionName(collectionConfig)}(\ - {@formatResourceFunctionParams(collectionConfig)}) + public static function {@function.name}(\ + {@formatResourceFunctionParams(function.resourceIdParams)}) { - return self::{@pathTemplateFunctionName(collectionConfig)}()->render([ - {@pathTemplateArgs(collectionConfig)}, + return self::{@function.pathTemplateGetterName}()->render([ + {@pathTemplateArgs(function.resourceIdParams)}, ]); } - + {@""} @end -@private formatResourceFunctionName(collectionConfig) - format{@resourceName(collectionConfig)} +@private formatResourceFunctionParams(resourceIdParams) + @join param : resourceIdParams on ", " + ${@param.name} + @end @end -@private formatResourceFunctionParams(collectionConfig) - @join param : collectionConfig.getNameTemplate.vars() on ", " - ${@context.lowerUnderscoreToLowerCamel(param)} +@private pathTemplateArgs(resourceIdParams) + @join param : resourceIdParams on ",".add(BREAK) + '{@param.templateKey}' => ${@param.name} @end @end -@private pathTemplateArgs(collectionConfig) - @join param : collectionConfig.getNameTemplate.vars() vertical on ", " - '{@param}' => ${@context.lowerUnderscoreToLowerCamel(param)} - @end +@private parseResourceFunction(function) + /** + * Parses the {@function.outputResourceId} from the given fully-qualified path which + * represents a {@function.entityName} resource. + */ + public static function {@function.name}(${@function.entityNameParamName}) + { + return self::{@function.pathTemplateGetterName}()\ + ->match(${@function.entityNameParamName})['{@function.outputResourceId}']; + } + {@""} @end -@private parseResourceFunction(collectionConfig) - @join subField : collectionConfig.getNameTemplate.vars() - @let fieldPath = context.upperCamelToLowerCamel(resourceName(collectionConfig)) - /** - * Parses the {@subField} from the given fully-qualified path which - * represents a {@context.lowerUnderscoreToLowerCamel(collectionConfig.getEntityName)} resource. - */ - public static function \ - parse{@context.lowerUnderscoreToUpperCamel(subField)}From{@resourceName(collectionConfig)}(\ - ${@fieldPath}) - { - return self::{@pathTemplateFunctionName(collectionConfig)}()->match(${@fieldPath})['{@subField}']; - } +@private pathTemplateGetterFunction(function) + private static function {@function.name}() + { + if (self::${@function.pathTemplateName} == null) { + self::${@function.pathTemplateName} = new PathTemplate('{@function.pattern}'); + } - @end - @end + return self::${@function.pathTemplateName}; + } + {@""} @end -@private resourceName(collectionConfig) - {@context.lowerUnderscoreToUpperCamel(collectionConfig.getEntityName)}Name +@private pageStreamingDescriptorFunction(xapiClass) + private static function getPageStreamingDescriptors() + { + @join descriptor : xapiClass.pageStreamingDescriptors + ${@descriptor.varName} = + new PageStreamingDescriptor([ + 'requestPageTokenField' => '{@descriptor.requestTokenFieldName}', + 'responsePageTokenField' => '{@descriptor.responseTokenFieldName}', + 'resourceField' => '{@descriptor.resourcesFieldName}', + ]); + @end + + $pageStreamingDescriptors = [ + @join descriptor : xapiClass.pageStreamingDescriptors + '{@descriptor.methodName}' => ${@descriptor.varName}, + @end + ]; + + return $pageStreamingDescriptors; + } + {@""} @end -@private pathTemplateFunction(collectionConfig) - private static function {@pathTemplateFunctionName(collectionConfig)}() +@private constructor(xapiClass) + // TODO(garrettjones): add channel (when supported in gRPC) + /** + * Constructor. + * + * @@param array $options { + * Optional. Options for configuring the service API wrapper. + * + * @@var string $serviceAddress The domain name of the API remote host. + * Default '{@xapiClass.serviceAddress}'. + * @@var mixed $port The port on which to connect to the remote host. Default {@xapiClass.servicePort}. + * @@var Grpc\ChannelCredentials $sslCreds + * A `ChannelCredentials` for use with an SSL-enabled channel. + * Default: a credentials object returned from + * Grpc\ChannelCredentials::createSsl() + * @@var array $scopes A string array of scopes to use when acquiring credentials. + * Default the scopes for the {@xapiClass.serviceTitle}. + * @@var array $retryingOverride + * An associative array of string => RetryOptions, where the keys + * are method names (e.g. 'createFoo'), that overrides default retrying + * settings. A value of null indicates that the method in question should + * not retry. + * @@var int $timeoutMillis The timeout in milliseconds to use for calls + * that don't use retries. For calls that use retries, + * set the timeout in RetryOptions. + * Default: 30000 (30 seconds) + * @@var string $appName The codename of the calling service. Default 'gax'. + * @@var string $appVersion The version of the calling service. + * Default: the current version of GAX. + * } + */ + public function __construct($options = []) { - if (self::${@pathTemplateConstantName(collectionConfig)} == null) { - self::${@pathTemplateConstantName(collectionConfig)} = new PathTemplate('{@collectionConfig.getNamePattern}'); + $defaultScopes = [ + @join scope : {@xapiClass.authScopes} + '{@scope}', + @end + ]; + $defaultOptions = [ + 'serviceAddress' => self::SERVICE_ADDRESS, + 'port' => self::DEFAULT_SERVICE_PORT, + 'scopes' => $defaultScopes, + 'retryingOverride' => null, + 'timeoutMillis' => self::DEFAULT_TIMEOUT_MILLIS, + 'appName' => 'gax', + 'appVersion' => self::_GAX_VERSION, + ]; + $options = array_merge($defaultOptions, $options); + + $headerDescriptor = new AgentHeaderDescriptor([ + 'clientName' => $options['appName'], + 'clientVersion' => $options['appVersion'], + 'codeGenName' => self::_CODEGEN_NAME, + 'codeGenVersion' => self::_CODEGEN_VERSION, + 'gaxVersion' => self::_GAX_VERSION, + 'phpVersion' => phpversion(), + ]); + + $defaultDescriptors = ['headerDescriptor' => $headerDescriptor]; + $this->descriptors = [ + @join methodKey : xapiClass.methodKeys + '{@methodKey}' => $defaultDescriptors, + @end + ]; + $pageStreamingDescriptors = self::getPageStreamingDescriptors(); + foreach ($pageStreamingDescriptors as $method => $pageStreamingDescriptor) { + $this->descriptors[$method]['pageStreamingDescriptor'] = $pageStreamingDescriptor; } - return self::${@pathTemplateConstantName(collectionConfig)}; + // TODO load the client config in a more package-friendly way + // https://github.com/googleapis/toolkit/issues/332 + $clientConfigJsonString = file_get_contents('{@xapiClass.clientConfigPath}'); + $clientConfig = json_decode($clientConfigJsonString, true); + $this->defaultCallSettings = + CallSettings::load('{@xapiClass.interfaceKey}', + $clientConfig, + $options['retryingOverride'], + GrpcConstants::getStatusCodeNames(), + $options['timeoutMillis']); + + $this->scopes = $options['scopes']; + + $generatedCreateStub = function ($hostname, $opts) { + return new {@xapiClass.grpcClientTypeName}($hostname, $opts); + }; + $createStubOptions = []; + if (!empty($options['sslCreds'])) { + $createStubOptions['sslCreds'] = $options['sslCreds']; + } + $this->grpcBootstrap = GrpcBootstrap::defaultInstance(); + $this->stub = $this->grpcBootstrap->createStub( + $generatedCreateStub, + $options['serviceAddress'], + $options['port'], + $createStubOptions); } - + {@""} @end -@private constructor(service) - @let className = context.getApiWrapperName(service), \ - jsonBaseName = {@context.upperCamelToLowerUnderscore(service.getSimpleName)}, \ - grpcClientName = context.getGrpcClientName(service) - // TODO(garrettjones): add channel (when supported in gRPC) - /** - * Constructor. - * - * @@param array $options { - * Optional. Options for configuring the service API wrapper. - * - * @@var string $serviceAddress The domain name of the API remote host. - * Default '{@context.getServiceConfig.getServiceAddress(service)}'. - * @@var mixed $port The port on which to connect to the remote host. Default {@context.getServiceConfig.getServicePort()}. - * @@var Grpc\ChannelCredentials $sslCreds - * A `ChannelCredentials` for use with an SSL-enabled channel. - * Default: a credentials object returned from - * Grpc\ChannelCredentials::createSsl() - * @@var array $scopes A string array of scopes to use when acquiring credentials. - * Default the scopes for the {@context.getServiceConfig.getTitle(service)}. - * @@var array $retryingOverride - * An associative array of string => RetryOptions, where the keys - * are method names (e.g. 'createFoo'), that overrides default retrying - * settings. A value of null indicates that the method in question should - * not retry. - * @@var int $timeoutMillis The timeout in milliseconds to use for calls - * that don't use retries. For calls that use retries, - * set the timeout in RetryOptions. - * Default: 30000 (30 seconds) - * @@var string $appName The codename of the calling service. Default 'gax'. - * @@var string $appVersion The version of the calling service. - * Default: the current version of GAX. - * } - */ - public function __construct($options = []) +@private apiMethods(xapiClass) + @join apiMethod : xapiClass.apiMethods + @let coreSampleCode = sampleCode(apiMethod) + {@methodDoc(apiMethod.doc, decorateSampleCode(apiMethod, coreSampleCode))} + @end + public function {@apiMethod.name}({@paramList(apiMethod.methodParams)}) { - $defaultScopes = [ - @join scope : context.getServiceConfig.getAuthScopes(service) - '{@scope}', - @end - ]; - $defaultOptions = [ - 'serviceAddress' => self::SERVICE_ADDRESS, - 'port' => self::DEFAULT_SERVICE_PORT, - 'scopes' => $defaultScopes, - 'retryingOverride' => null, - 'timeoutMillis' => self::DEFAULT_TIMEOUT_MILLIS, - 'appName' => 'gax', - 'appVersion' => self::_GAX_VERSION, - ]; - $options = array_merge($defaultOptions, $options); - - $headerDescriptor = new AgentHeaderDescriptor([ - 'clientName' => $options['appName'], - 'clientVersion' => $options['appVersion'], - 'codeGenName' => self::_CODEGEN_NAME, - 'codeGenVersion' => self::_CODEGEN_VERSION, - 'gaxVersion' => self::_GAX_VERSION, - 'phpVersion' => phpversion(), - ]); - - $defaultDescriptors = ['headerDescriptor' => $headerDescriptor]; - $this->descriptors = [ - @join method : service.getMethods - '{@context.upperCamelToLowerCamel(method.getSimpleName)}' => $defaultDescriptors, - @end - ]; - $pageStreamingDescriptors = self::getPageStreamingDescriptors(); - foreach ($pageStreamingDescriptors as $method => $pageStreamingDescriptor) { - $this->descriptors[$method]['pageStreamingDescriptor'] = $pageStreamingDescriptor; - } + $request = new {@apiMethod.requestTypeName}(); + @join param : apiMethod.requiredRequestObjectParams + {@setRequiredFieldCall(param)} + @end + @join param : apiMethod.optionalRequestObjectParams + {@setOptionalFieldCall(param)} + @end - // TODO load the client config in a more package-friendly way - $clientConfigJsonString = file_get_contents('./resources/{@jsonBaseName}_client_config.json'); - $clientConfig = json_decode($clientConfigJsonString, true); - $this->defaultCallSettings = - CallSettings::load('{@context.getServiceName(service)}', - $clientConfig, - $options['retryingOverride'], - GrpcConstants::getStatusCodeNames(), - $options['timeoutMillis']); - - $this->scopes = $options['scopes']; - - $generatedCreateStub = function ($hostname, $opts) { - return new {@grpcClientName}($hostname, $opts); - }; - $createStubOptions = []; - if (!empty($options['sslCreds'])) { - $createStubOptions['sslCreds'] = $options['sslCreds']; - } - $this->grpcBootstrap = GrpcBootstrap::defaultInstance(); - $this->stub = $this->grpcBootstrap->createStub( - $generatedCreateStub, - $options['serviceAddress'], - $options['port'], - $createStubOptions); - } - @end -@end + $mergedSettings = $this->defaultCallSettings['{@apiMethod.key}']->merge( + new CallSettings($callSettings)); + $callable = ApiCallable::createApiCall( + $this->stub, '{@apiMethod.grpcMethodName}', $mergedSettings, $this->descriptors['{@apiMethod.key}']); -@private apiMethods(service) - @join method : service.getMethods on BREAK.add(BREAK) - @let callableConstant = context.upperCamelToUpperUnderscore(method.getSimpleName), \ - methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - inTypeName = context.typeName(method.getInputType), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - requiredFields = methodConfig.getRequiredFields(), \ - optionalFields = methodConfig.getOptionalFields() - {@methodDoc(service, method)} - public function {@methodName}({@apiMethodParams(requiredFields)}{@commonParams(requiredFields)}) - { - {@requestObjectCreation(inTypeName, requiredFields, optionalFields)} - - $mergedSettings = $this->defaultCallSettings['{@methodName}']->merge( - new CallSettings($callSettings)); - $callable = ApiCallable::createApiCall( - $this->stub, '{@method.getSimpleName}', $mergedSettings, $this->descriptors['{@methodName}']); - - return $callable( - $request, - [], - ['call_credentials_callback' => $this->createCredentialsCallback()]); - } - @end + return $callable( + $request, + [], + ['call_credentials_callback' => $this->createCredentialsCallback()]); + } + {@""} @end @end -@private apiMethodParams(requiredFields) - @join field : requiredFields on ", " - @let paramName = context.lowerUnderscoreToLowerCamel(field.getSimpleName) - ${@paramName} +@private paramList(params) + @join param : params on ", " + @if param.defaultValue + ${@param.name} = {@param.defaultValue} + @else + ${@param.name} @end @end @end -@private commonParams(requiredFields) - @if requiredFields - , $optionalArgs = [], $callSettings = [] +@private setRequiredFieldCall(param) + @if param.isMap + foreach (${@param.name} as $key => $value) { + $request->{@param.setCallName}((new {@param.elementTypeName}())->setKey($key)->setValue($value)); + } @else - $optionalArgs = [], $callSettings = [] - @end -@end - -@private requestObjectCreation(inTypeName, requiredFields, optionalFields) - $request = new {@inTypeName}(); - @join field : requiredFields - {@setRequiredFieldCall(field)} - @end - @join field : optionalFields - {@setOptionalFieldCall(field)} + @if param.isArray + foreach (${@param.name} as $elem) { + $request->{@param.setCallName}($elem); + } + @else + $request->{@param.setCallName}(${@param.name}); + @end @end @end -@private setRequiredFieldCall(field) - @let paramUpperCamel = context.lowerUnderscoreToUpperCamel(field.getSimpleName), \ - paramLowerCamel = context.lowerUnderscoreToLowerCamel(field.getSimpleName) - @if field.getType.isMap - @let fullyQualifiedEntryName = context.fullyQualifiedName(field.getType), \ - entryName = context.getTypeName(fullyQualifiedEntryName) - foreach (${@paramLowerCamel} as $key => $value) { - $request->add{@paramUpperCamel}((new {@entryName}())->setKey($key)->setValue($value)); - } - @end +@private setOptionalFieldCall(param) + if (isset($optionalArgs['{@param.name}'])) { + @if param.isMap + // TODO make this work + // https://github.com/googleapis/toolkit/issues/333 + putAll... @else - @if field.isRepeated - foreach (${@paramLowerCamel} as $elem) { - $request->add{@paramUpperCamel}($elem); + @if param.isArray + foreach ($optionalArgs['{@param.name}'] as $elem) { + $request->{@param.setCallName}($elem); } @else - $request->set{@paramUpperCamel}(${@paramLowerCamel}); + $request->{@param.setCallName}($optionalArgs['{@param.name}']); @end @end - @end -@end - -@private setOptionalFieldCall(field) - @let paramUpperCamel = context.lowerUnderscoreToUpperCamel(field.getSimpleName), \ - paramLowerCamel = context.lowerUnderscoreToLowerCamel(field.getSimpleName) - if (isset($optionalArgs['{@paramLowerCamel}'])) { - @if field.getType.isMap - // TODO make this work - putAll... - @else - @if field.isRepeated - foreach ($optionalArgs['{@paramLowerCamel}'] as $elem) { - $request->add{@paramUpperCamel}($elem); - } - @else - $request->set{@paramUpperCamel}($optionalArgs['{@paramLowerCamel}']); - @end - @end - } - @end + } @end -@private methodDoc(service, method) +@private methodDoc(apiMethodDoc, methodSampleCode) /** - {@docLinesFromStr(context.getDescription(method))} + @join commentLine : apiMethodDoc.mainDocLines + {@""} * {@commentLine} + @end * * Sample code: * ``` - {@createMethodSampleDoc(service, method)} + @join sampleLine : util.getDocLines(methodSampleCode) + {@""} * {@sampleLine} + @end * ``` - {@requiredArgsDoc(service, method)} - {@optionalArgsDoc(service, method)} - * @@param array $callSettings { - * Optional. - * @@var Google\GAX\RetrySettings $retrySettings - * Retry settings to use for this call. If present, then - * $timeout is ignored. - * @@var int $timeoutMillis - * Timeout to use for this call. Only used if $retrySettings - * is not set. - * } - {@docReturnLine(service, method)} + @if apiMethodDoc.paramDocs + {@""} * + @join doc : apiMethodDoc.paramDocs + {@paramDoc(doc)} + @end + @end + @if apiMethodDoc.returnTypeName + {@""} * + * @@return {@apiMethodDoc.returnTypeName} + @end + * * @@throws Google\GAX\ApiException if the remote call fails */ + {@""} @end -@private createMethodSampleDoc(service, method) - @let methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - ApiName = context.getApiWrapperName(service), \ - apiName = context.upperCamelToLowerCamel(ApiName), \ - methodName = context.upperCamelToLowerCamel(method.getSimpleName), \ - requiredFields = methodConfig.getRequiredFields() - {@docLinesFromStr(methodSampleDoc(context.newPhpDocConfigBuilder()\ - .setApiName(ApiName) \ - .setMethodName(methodName) \ - .setFieldInitCode(context, service, method, requiredFields) \ - .setPagedVariant(methodConfig.isPageStreaming) \ - .setReturnType(context.returnTypeOrEmpty(method.getOutputType)) \ - .build()))} - @end -@end - -@snippet docLinesFromStr(str) - @join commentLine : context.php.getDocLines(str) - {@commentLine} +@private paramDoc(doc) + @switch doc.type + @case "SimpleParamDocView" + {@simpleParamDoc(doc)} + @case "MapParamDocView" + {@mapParamDoc(doc)} + @default + $unhandledCase: {@doc.type}$ @end @end -@private requiredArgsDoc(service, method) - {@""} * - @let methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method) - @join param : methodConfig.getRequiredFields() - @join commentLine : context.php.getDocLinesWithPrefix(context.getDescription(param), requiredParamDocLinePrefix(param)) - {@commentLine} - @end +@private simpleParamDoc(doc) + {@""} * @@param {@doc.typeName} ${@doc.paramName} {@doc.firstLine} + @if doc.remainingLines + @join commentLine : doc.remainingLines + {@""} * {@commentLine} @end @end @end -@private requiredParamDocLinePrefix(param) - @@param {@context.typeName(param.getType)} ${@context.lowerUnderscoreToLowerCamel(param.getSimpleName)} {@""} -@end - -@private optionalArgsDoc(service, method) - @let methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - optionalFields = methodConfig.getOptionalFields() - @if optionalFields - {@""} * @@param array $optionalArgs { - * Optional. - @join param : optionalFields - @if isPageSizeField(param, methodConfig) - {@""} * @@var int ${@context.lowerUnderscoreToLowerCamel(methodConfig.getPageStreaming.getPageSizeField.getSimpleName)} - * The maximum number of resources contained in the underlying API - * response. If page streaming is performed per-resource, this - * parameter does not affect the return value. If page streaming is - * performed per-page, this determines the maximum number of - * resources in a page. - @else - @join commentLine : context.php.getDocLinesWithPrefixes(context.getDescription(param), optionalParamDocLinePrefix(param), " ") - {@commentLine} - @end - @end - @end - * } - @else - {@""} * @@param array $optionalArgs { - * Optional. There are no optional parameters for this method yet; - * this $optionalArgs parameter reserves a spot for future ones. - * } +@private mapParamDoc(doc) + {@""} * @@param {@doc.typeName} ${@doc.paramName} { + * {@doc.firstLine} + @if doc.remainingLines + @join commentLine : doc.remainingLines + {@""} * {@commentLine} @end @end -@end - -@private isPageSizeField(param, methodConfig) - @if methodConfig.isPageStreaming - @if methodConfig.getPageStreaming.hasPageSizeField - @if param.equals(methodConfig.getPageStreaming.getPageSizeField) - TRUE + @if doc.arrayKeyDocs + @join simpleParamDoc : doc.arrayKeyDocs + {@""} * @@var {@simpleParamDoc.typeName} ${@simpleParamDoc.paramName} + @if simpleParamDoc.firstLine + {@""} * {@simpleParamDoc.firstLine} @end - @end - @end -@end - -@private optionalParamDocLinePrefix(param) - {@""} @@var {@context.typeName(param.getType)} ${@context.lowerUnderscoreToLowerCamel(param.getSimpleName)} {@""} -@end - -@private docReturnLine(service, method) - @let qualifiedOutTypeName = context.fullyQualifiedName(method.getOutputType), \ - methodConfig = context.getApiConfig.getInterfaceConfig(service).getMethodConfig(method), \ - isPageStreaming = methodConfig.isPageStreaming - @if not(context.messages.isEmptyType(method.getOutputType)) - {@""} * - @if isPageStreaming - {@""} * @@return Google\GAX\PageAccessor - @else - {@""} * @@return {@qualifiedOutTypeName} + @if simpleParamDoc.remainingLines + @join commentLine : simpleParamDoc.remainingLines + {@""} * {@commentLine} + @end @end - @end @end - * + * } @end @private cleanupSection() diff --git a/src/main/resources/com/google/api/codegen/php/method_sample.snip b/src/main/resources/com/google/api/codegen/php/method_sample.snip index fff9f1badf..d689a4cb3c 100644 --- a/src/main/resources/com/google/api/codegen/php/method_sample.snip +++ b/src/main/resources/com/google/api/codegen/php/method_sample.snip @@ -1,153 +1,108 @@ -@snippet methodSampleDoc(docConfig) - @let ApiName = docConfig.getApiName, \ - apiName = context.upperCamelToLowerCamel(ApiName), \ - methodName = docConfig.getMethodName(), \ - returnType = docConfig.getReturnType(), \ - initCodeSpec = docConfig.getInitCode() - try { - ${@apiName} = new {@ApiName}(); - {@initCode(initCodeSpec)} - @if docConfig.isPagedVariant() - foreach ({@methodCallSampleCode(methodName, apiName, initCodeSpec)} as $element) { - // doThingsWith(element); - } - @else - @if returnType - $response = {@methodCallSampleCode(methodName, apiName, initCodeSpec)}; - @else - {@methodCallSampleCode(methodName, apiName, initCodeSpec)}; - @end - @end - } finally { - if (isset(${@apiName})) { - ${@apiName}->close(); - } +@extends "php/mvvm_common.snip" + +@snippet decorateSampleCode(apiMethod, coreSampleCode) + try { + ${@apiMethod.apiVariableName} = new {@apiMethod.apiClassName}(); + {@initCode(apiMethod.initCode)} + {@coreSampleCode} + } finally { + if (isset(${@apiMethod.apiVariableName})) { + ${@apiMethod.apiVariableName}->close(); } - @end -@end - -@private methodCallSampleCode(methodName, apiName, initCodeSpec) - ${@apiName}->{@methodName}({@argList(initCodeSpec.getArgFields)}) + } @end -@private initCode(initCodeSpec) - @join line : initCodeSpec.getLines() - @switch line.getLineType.toString() - @case "StructureInitLine" - {@initLineStructure(line)} - @case "ListInitLine" - {@initLineList(line)} - @case "SimpleInitLine" - {@initLineSimple(line)} - @case "MapInitLine" - {@initLineMap(initCodeSpec, line)} +@snippet sampleCode(apiMethod) + @switch apiMethod.type.toString + @case "OptionalArrayMethod" + {@optionalArrayMethodSampleCode(apiMethod)} + @case "PagedOptionalArrayMethod" + {@pagedOptionalArrayMethodSampleCode(apiMethod)} @default - {@unhandledCase()} + $unhandledCase: {@apiMethod.type.toString}$ @end - @end @end -@private initLineStructure(line) - {@formattedIdentifier(line)} = new {@context.typeName(line.getType)}(); - @join fieldSetting : line.getFieldSettings - @let setCallName = setCallName(fieldSetting) - {@formattedIdentifier(line)}->{@setCallName}({@formattedIdentifier(fieldSetting)}); +@private optionalArrayMethodSampleCode(apiMethod) + @if apiMethod.hasReturnValue + $response = {@methodCallSampleCode(apiMethod)}; + @else + {@methodCallSampleCode(apiMethod)}; @end - @end @end -@private initLineList(line) - {@formattedIdentifier(line)} = [{@initList(line)}]; +@private pagedOptionalArrayMethodSampleCode(apiMethod) + foreach ({@methodCallSampleCode(apiMethod)} as $element) { + // doThingsWith(element); + } @end -@private initList(line) - @join identifier : line.getElementIdentifiers on ", " - {@unformattedIdentifier(identifier)} - @end +@private methodCallSampleCode(apiMethod) + ${@apiMethod.apiVariableName}->{@apiMethod.name}(\ + {@sampleMethodCallArgList(apiMethod.initCode.fieldSettings)}) @end -@private initLineMap(initCodeSpec, line) - @if context.initLineIsParameter(initCodeSpec, line) - {@formattedIdentifier(line)} = [{@initMap(line)}]; - @else - {@formattedIdentifier(line)} = []; - @join key : line.getElementIdentifierKeys vertical - @let identifierValue = line.getElementIdentifierValue(key),\ - entryIdentifier = getEntryIdentifier(line), \ - fullyQualifiedEntryName = context.fullyQualifiedName(line.getElementType), \ - entryName = context.getTypeName(fullyQualifiedEntryName) - {@entryIdentifier} = new {@entryName}(); - {@entryIdentifier}->setKey({@context.renderPrimitiveValue(line.getKeyType, key)}); - {@entryIdentifier}->setValue({@unformattedIdentifier(identifierValue)}); - array_push({@formattedIdentifier(line)}, {@entryIdentifier}); - @end +@private sampleMethodCallArgList(fieldSettings) + @join fieldSetting : fieldSettings on ", " + ${@fieldSetting.identifier} @end - @end @end -@private initMap(line) - @join key : line.getElementIdentifierKeys vertical - @let identifierValue = line.getElementIdentifierValue(key),\ - entryIdentifier = getEntryIdentifier(line) - {@context.renderPrimitiveValue(line.getKeyType, key)} => {@unformattedIdentifier(identifierValue)}, +@private initCode(initCodeSpec) + @join line : initCodeSpec.lines + @switch line.lineType.toString + @case "StructureInitLine" + {@initLineStructure(line)} + @case "ListInitLine" + {@initLineList(line)} + @case "MapInitLine" + {@initLineMap(line)} + @case "SimpleInitLine" + {@initLineSimple(line)} + @default + $unhandledCase: {@line.lineType.toString}$ + @end @end - @end -@end - -@private initLineSimple(line) - {@formattedIdentifier(line)} = {@initValue(line)}; @end -@private getEntryIdentifier(lineOrFieldSetting) - {@unformattedIdentifier(lineOrFieldSetting.getIdentifier)}Entry -@end - -@private formattedIdentifier(lineOrFieldSetting) - {@formattedIdentifier(lineOrFieldSetting.getIdentifier, lineOrFieldSetting.getInitValueConfig.hasFormattingConfig)} +@private initLineStructure(line) + ${@line.identifier} = new {@line.typeName}(); + @join fieldSetting : line.fieldSettings + ${@line.identifier}->{@fieldSetting.fnSetFunctionCallName}(${@fieldSetting.identifier}); + @end @end -@private unformattedIdentifier(identifier) - {@formattedIdentifier(identifier, FALSE)} +@private initLineList(line) + ${@line.identifier} = [{@varList(line.elementIdentifiers)}]; @end -@private formattedIdentifier(identifier, isFormatted) - @if isFormatted - $formatted{@context.lowerUnderscoreToUpperCamel(identifier)} - @else - ${@context.lowerUnderscoreToLowerCamel(identifier)} +@snippet varList(args) + @join arg : args on ", " + ${@arg} @end @end -@private initValue(line) - @let metadata = line.getInitValueConfig - @if metadata.hasFormattingConfig() - {@metadata.getApiWrapperName}::{@formatResourceFunctionName(metadata.getCollectionConfig)}({@formatResourceFunctionArgs(metadata.getCollectionConfig)}) - @else - {@context.zeroValue(line.getType)} - @end - @end +@private initLineMap(line) + ${@line.identifier} = [{@keyVarList(line.initEntries)}]; @end -@private formatResourceFunctionArgs(collectionConfig) - @join param : collectionConfig.getNameTemplate.vars() on ", " - "[{@context.lowerUnderscoreToUpperUnderscore(param)}]" +@private keyVarList(mapEntries) + @join mapEntry : mapEntries + {@mapEntry.key} => ${@mapEntry.value}, @end @end -@private formatResourceFunctionName(collectionConfig) - format{@resourceName(collectionConfig)} -@end - -@private resourceName(collectionConfig) - {@context.lowerUnderscoreToUpperCamel(collectionConfig.getEntityName)}Name -@end - -@snippet setCallName(field) - set{@context.lowerUnderscoreToUpperCamel(field.getFieldName)} +@private initLineSimple(line) + ${@line.identifier} = {@renderInitValue(line.initValue)}; @end -@private argList(fieldSettings) - @join fieldSetting : fieldSettings on ", " - {@formattedIdentifier(fieldSetting)} - @end +@private renderInitValue(initValue) + @switch initValue.type + @case "SimpleInitValueView" + {@initValue.initialValue} + @case "FormattedInitValueView" + {@initValue.apiWrapperName}::{@initValue.formatFunctionName}({@argList(initValue.formatArgs)}) + @default + $unhandledCase: {@initValue.type}$ + @end @end diff --git a/src/main/resources/com/google/api/codegen/php/mvvm_common.snip b/src/main/resources/com/google/api/codegen/php/mvvm_common.snip new file mode 100644 index 0000000000..f33115a7c5 --- /dev/null +++ b/src/main/resources/com/google/api/codegen/php/mvvm_common.snip @@ -0,0 +1,6 @@ + +@snippet argList(args) + @join arg : args on ", " + {@arg} + @end +@end diff --git a/src/main/resources/com/google/api/codegen/py/method_sample.snip b/src/main/resources/com/google/api/codegen/py/method_sample.snip index 69d7c44510..a727165a5d 100644 --- a/src/main/resources/com/google/api/codegen/py/method_sample.snip +++ b/src/main/resources/com/google/api/codegen/py/method_sample.snip @@ -85,7 +85,7 @@ # Helper method for initLineList() @private initList(line) @join identifier : line.getElementIdentifiers on ", " - {@identifier} + {@identifier.toLowerUnderscore} @end @end @@ -93,7 +93,7 @@ @private initMap(line) @join key : line.getElementIdentifierKeys vertical on "," @let identifierValue = line.getElementIdentifierValue(key) - {@context.renderPrimitiveValue(line.getKeyType, key)}: {@identifierValue} + {@context.renderPrimitiveValue(line.getKeyType, key)}: {@identifierValue.toLowerUnderscore} @end @end @end @@ -105,7 +105,7 @@ # Properly format an identifier for this language @private formattedIdentifier(lineOrFieldSetting) - {@lineOrFieldSetting.getIdentifier} + {@lineOrFieldSetting.getIdentifier.toLowerUnderscore} @end # Value for simple argument diff --git a/src/test/java/com/google/api/codegen/JavaCodeGeneratorTest.java b/src/test/java/com/google/api/codegen/JavaCodeGeneratorTest.java index 9439e02b3b..0d82ae27ea 100644 --- a/src/test/java/com/google/api/codegen/JavaCodeGeneratorTest.java +++ b/src/test/java/com/google/api/codegen/JavaCodeGeneratorTest.java @@ -32,7 +32,7 @@ public class JavaCodeGeneratorTest extends GapicTestBase { public JavaCodeGeneratorTest( String name, String idForFactory, String[] gapicConfigFileNames, String snippetName) { super(name, idForFactory, gapicConfigFileNames, snippetName); - getTestDataLocator().addTestDataSource(com.google.api.codegen.java.JavaGapicContext.class, ""); + getTestDataLocator().addTestDataSource(com.google.api.codegen.java.JavaContextCommon.class, ""); } /** diff --git a/src/test/java/com/google/api/codegen/PhpCodeGeneratorTest.java b/src/test/java/com/google/api/codegen/PhpCodeGeneratorTest.java index fac3abe9f7..ec71910d27 100644 --- a/src/test/java/com/google/api/codegen/PhpCodeGeneratorTest.java +++ b/src/test/java/com/google/api/codegen/PhpCodeGeneratorTest.java @@ -32,7 +32,7 @@ public class PhpCodeGeneratorTest extends GapicTestBase { public PhpCodeGeneratorTest( String name, String idForFactory, String[] gapicConfigFileNames, String snippetName) { super(name, idForFactory, gapicConfigFileNames, snippetName); - getTestDataLocator().addTestDataSource(com.google.api.codegen.php.PhpGapicContext.class, ""); + getTestDataLocator().addTestDataSource(com.google.api.codegen.php.PhpContext.class, ""); } /** diff --git a/src/test/java/com/google/api/codegen/testdata/csharp_wrapper_library.baseline b/src/test/java/com/google/api/codegen/testdata/csharp_wrapper_library.baseline index 1ab4c1e118..4f5e1affae 100644 --- a/src/test/java/com/google/api/codegen/testdata/csharp_wrapper_library.baseline +++ b/src/test/java/com/google/api/codegen/testdata/csharp_wrapper_library.baseline @@ -695,13 +695,13 @@ namespace Google.Example.Library.V1 /// /// The default LibraryService scopes are: /// - /// "https://www.googleapis.com/auth/library" /// "https://www.googleapis.com/auth/cloud-platform" + /// "https://www.googleapis.com/auth/library" /// /// public static IReadOnlyList DefaultScopes { get; } = new ReadOnlyCollection(new[] { - "https://www.googleapis.com/auth/library", "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/library", }); ///
diff --git a/src/test/java/com/google/api/codegen/testdata/go_main_library.baseline b/src/test/java/com/google/api/codegen/testdata/go_main_library.baseline index 437d4d986b..23b6108bbc 100644 --- a/src/test/java/com/google/api/codegen/testdata/go_main_library.baseline +++ b/src/test/java/com/google/api/codegen/testdata/go_main_library.baseline @@ -62,8 +62,8 @@ func defaultClientOptions() []option.ClientOption { return []option.ClientOption{ option.WithEndpoint("library-example.googleapis.com:443"), option.WithScopes( - "https://www.googleapis.com/auth/library", "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/library", ), } } diff --git a/src/test/java/com/google/api/codegen/testdata/java_fragments_library.baseline b/src/test/java/com/google/api/codegen/testdata/java_fragments_library.baseline deleted file mode 100644 index 7c153c636d..0000000000 --- a/src/test/java/com/google/api/codegen/testdata/java_fragments_library.baseline +++ /dev/null @@ -1,48 +0,0 @@ -/* - * PRE-REQUISITES: - * --------------- - * 1. If not already done, enable the LibraryService API and check quota for your project at - * https://console.developers.google.com/apis/api/libraryService_component/quotas - * 2. To install the client library on Maven or Gradle, check installation instructions at - * https://github.com/google/google-api-java-client. - * On other build systems, you can add the jar files to your project from - * https://developers.google.com/resources/api-libraries/download/libraryService/com.google.gcloud.pubsub.spi/java - * 3. This sample uses Application Default Credentials for Auth. If not already done, install the gcloud CLI from - * https://cloud.google.com/sdk/ and run 'gcloud auth login' - */ - -import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; -import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; -import com.google.api.client.http.HttpTransport; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.example.library.v1.CreateShelfRequest; -import com.google.example.library.v1.Shelf; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.Collections; - - -@javax.annotation.Generated("by the sample snippet generator") -public class LibraryServiceSample { - public static void main(String[] args) throws IOException, GeneralSecurityException { - // Authentication is provided by the 'gcloud' tool when running locally - // and by built-in service accounts when running on GAE, GCE, or GKE. - GoogleCredential credential = GoogleCredential.getApplicationDefault(); - - // The createScopedRequired method returns true when running on GAE or a local developer - // machine. In that case, the desired scopes must be passed in manually. When the code is - // running in GCE, GKE or a Managed VM, the scopes are pulled from the GCE metadata server. - // See https://developers.google.com/identity/protocols/application-default-credentials for more information. - if (credential.createScopedRequired()) { - credential = credential.createScoped(Collections.singletonList("https://www.googleapis.com/auth/cloud-platform")); - } - - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); - LibraryService libraryServiceService = new LibraryService.Builder(httpTransport, jsonFactory, credential) - .setApplicationName("Google Cloud Platform Sample") - .build(); - - } -} diff --git a/src/test/java/com/google/api/codegen/testdata/java_main_library.baseline b/src/test/java/com/google/api/codegen/testdata/java_main_library.baseline index 359fdf465a..b83727a11c 100644 --- a/src/test/java/com/google/api/codegen/testdata/java_main_library.baseline +++ b/src/test/java/com/google/api/codegen/testdata/java_main_library.baseline @@ -40,6 +40,7 @@ import com.google.example.library.v1.PublishSeriesResponse; import com.google.example.library.v1.Shelf; import com.google.example.library.v1.SomeMessage; import com.google.example.library.v1.UpdateBookIndexRequest; +import com.google.example.library.v1.UpdateBookIndexRequest.IndexMapEntry; import com.google.example.library.v1.UpdateBookRequest; import com.google.protobuf.ByteString; import com.google.protobuf.Empty; @@ -52,8 +53,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; - - // AUTO-GENERATED DOCUMENTATION AND SERVICE /** * Service Description: This API represents a simple digital library. It lets you manage Shelf @@ -127,22 +126,19 @@ public class LibraryServiceApi implements AutoCloseable { private final ApiCallable createShelfCallable; private final ApiCallable getShelfCallable; private final ApiCallable listShelvesCallable; - private final ApiCallable> - listShelvesPagedCallable; + private final ApiCallable> listShelvesPagedCallable; private final ApiCallable deleteShelfCallable; private final ApiCallable mergeShelvesCallable; private final ApiCallable createBookCallable; private final ApiCallable publishSeriesCallable; private final ApiCallable getBookCallable; private final ApiCallable listBooksCallable; - private final ApiCallable> - listBooksPagedCallable; + private final ApiCallable> listBooksPagedCallable; private final ApiCallable deleteBookCallable; private final ApiCallable updateBookCallable; private final ApiCallable moveBookCallable; private final ApiCallable listStringsCallable; - private final ApiCallable> - listStringsPagedCallable; + private final ApiCallable> listStringsPagedCallable; private final ApiCallable addCommentsCallable; private final ApiCallable getBookFromArchiveCallable; private final ApiCallable updateBookIndexCallable; @@ -175,7 +171,8 @@ public class LibraryServiceApi implements AutoCloseable { */ public static final String formatBookName(String shelf, String book) { return BOOK_PATH_TEMPLATE.instantiate( - "shelf", shelf,"book", book); + "shelf", shelf, + "book", book); } /** @@ -184,7 +181,8 @@ public class LibraryServiceApi implements AutoCloseable { */ public static final String formatArchivedBookName(String archivePath, String book) { return ARCHIVED_BOOK_PATH_TEMPLATE.instantiate( - "archive_path", archivePath,"book", book); + "archive_path", archivePath, + "book", book); } /** @@ -227,7 +225,6 @@ public class LibraryServiceApi implements AutoCloseable { return ARCHIVED_BOOK_PATH_TEMPLATE.parse(archivedBookName).get("book"); } - /** * Constructs an instance of LibraryServiceApi with default settings. */ @@ -300,8 +297,6 @@ public class LibraryServiceApi implements AutoCloseable { } } - // ----- createShelf ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Creates a shelf, and returns the new Shelf. @@ -343,7 +338,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - private Shelf createShelf(CreateShelfRequest request) { + private final Shelf createShelf(CreateShelfRequest request) { return createShelfCallable().call(request); } @@ -368,8 +363,6 @@ public class LibraryServiceApi implements AutoCloseable { return createShelfCallable; } - // ----- getShelf ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Gets a shelf. @@ -413,7 +406,6 @@ public class LibraryServiceApi implements AutoCloseable { */ public final Shelf getShelf(String name, SomeMessage message) { SHELF_PATH_TEMPLATE.validate(name); - GetShelfRequest request = GetShelfRequest.newBuilder() .setName(name) @@ -443,8 +435,6 @@ public class LibraryServiceApi implements AutoCloseable { */ public final Shelf getShelf(String name, SomeMessage message, com.google.example.library.v1.StringBuilder stringBuilder) { SHELF_PATH_TEMPLATE.validate(name); - - GetShelfRequest request = GetShelfRequest.newBuilder() .setName(name) @@ -474,7 +464,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - public Shelf getShelf(GetShelfRequest request) { + public final Shelf getShelf(GetShelfRequest request) { return getShelfCallable().call(request); } @@ -501,8 +491,6 @@ public class LibraryServiceApi implements AutoCloseable { return getShelfCallable; } - // ----- listShelves ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Lists shelves. @@ -511,12 +499,11 @@ public class LibraryServiceApi implements AutoCloseable { *

    * try (LibraryServiceApi libraryServiceApi = LibraryServiceApi.createWithDefaults()) {
    *
-   *   for (Shelf elements : libraryServiceApi.listShelves()) {
-   *     // doThingsWith(elements);
+   *   for (Shelf element : libraryServiceApi.listShelves()) {
+   *     // doThingsWith(element);
    *   }
    * }
    * 
- * * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ public final PageAccessor listShelves() { @@ -536,8 +523,8 @@ public class LibraryServiceApi implements AutoCloseable { * try (LibraryServiceApi libraryServiceApi = LibraryServiceApi.createWithDefaults()) { * ListShelvesRequest request = ListShelvesRequest.newBuilder() * .build(); - * for (Shelf elements : libraryServiceApi.listShelves(request)) { - * // doThingsWith(elements); + * for (Shelf element : libraryServiceApi.listShelves(request)) { + * // doThingsWith(element); * } * } *
@@ -561,8 +548,8 @@ public class LibraryServiceApi implements AutoCloseable { * .build(); * ListenableFuture<PageAccessor<Shelf>> future = libraryServiceApi.listShelvesPagedCallable().futureCall(request); * // Do something - * for (Shelf elements : future.get()) { - * // doThingsWith(elements); + * for (Shelf element : future.get()) { + * // doThingsWith(element); * } * } * @@ -582,8 +569,8 @@ public class LibraryServiceApi implements AutoCloseable { * .build(); * while (true) { * ListShelvesResponse response = libraryServiceApi.listShelvesCallable().call(request); - * for (Shelf elements : response.getShelvesList()) { - * // doThingsWith(elements); + * for (Shelf element : response.getShelvesList()) { + * // doThingsWith(element); * } * String nextPageToken = response.getNextPageToken(); * if (!Strings.isNullOrEmpty(nextPageToken)) { @@ -599,8 +586,6 @@ public class LibraryServiceApi implements AutoCloseable { return listShelvesCallable; } - // ----- deleteShelf ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Deletes a shelf. @@ -643,7 +628,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - private void deleteShelf(DeleteShelfRequest request) { + private final void deleteShelf(DeleteShelfRequest request) { deleteShelfCallable().call(request); } @@ -668,8 +653,6 @@ public class LibraryServiceApi implements AutoCloseable { return deleteShelfCallable; } - // ----- mergeShelves ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Merges two shelves by adding all books from the shelf named @@ -722,7 +705,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - public Shelf mergeShelves(MergeShelvesRequest request) { + public final Shelf mergeShelves(MergeShelvesRequest request) { return mergeShelvesCallable().call(request); } @@ -751,8 +734,6 @@ public class LibraryServiceApi implements AutoCloseable { return mergeShelvesCallable; } - // ----- createBook ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Creates a book. @@ -772,7 +753,6 @@ public class LibraryServiceApi implements AutoCloseable { */ public final Book createBook(String name, Book book) { SHELF_PATH_TEMPLATE.validate(name); - CreateBookRequest request = CreateBookRequest.newBuilder() .setName(name) @@ -801,7 +781,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - public Book createBook(CreateBookRequest request) { + public final Book createBook(CreateBookRequest request) { return createBookCallable().call(request); } @@ -828,8 +808,6 @@ public class LibraryServiceApi implements AutoCloseable { return createBookCallable; } - // ----- publishSeries ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Creates a series of books. @@ -850,8 +828,6 @@ public class LibraryServiceApi implements AutoCloseable { * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ public final PublishSeriesResponse publishSeries(Shelf shelf, List books, int edition) { - - PublishSeriesRequest request = PublishSeriesRequest.newBuilder() .setShelf(shelf) @@ -881,7 +857,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - public PublishSeriesResponse publishSeries(PublishSeriesRequest request) { + public final PublishSeriesResponse publishSeries(PublishSeriesRequest request) { return publishSeriesCallable().call(request); } @@ -908,8 +884,6 @@ public class LibraryServiceApi implements AutoCloseable { return publishSeriesCallable; } - // ----- getBook ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Gets a book. @@ -952,7 +926,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - private Book getBook(GetBookRequest request) { + private final Book getBook(GetBookRequest request) { return getBookCallable().call(request); } @@ -977,8 +951,6 @@ public class LibraryServiceApi implements AutoCloseable { return getBookCallable; } - // ----- listBooks ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Lists books in a shelf. @@ -988,8 +960,8 @@ public class LibraryServiceApi implements AutoCloseable { * try (LibraryServiceApi libraryServiceApi = LibraryServiceApi.createWithDefaults()) { * String formattedName = LibraryServiceApi.formatShelfName("[SHELF]"); * String filter = ""; - * for (Book elements : libraryServiceApi.listBooks(formattedName, filter)) { - * // doThingsWith(elements); + * for (Book element : libraryServiceApi.listBooks(formattedName, filter)) { + * // doThingsWith(element); * } * } * @@ -1000,7 +972,6 @@ public class LibraryServiceApi implements AutoCloseable { */ public final PageAccessor listBooks(String name, String filter) { SHELF_PATH_TEMPLATE.validate(name); - ListBooksRequest request = ListBooksRequest.newBuilder() .setName(name) @@ -1020,8 +991,8 @@ public class LibraryServiceApi implements AutoCloseable { * ListBooksRequest request = ListBooksRequest.newBuilder() * .setName(formattedName) * .build(); - * for (Book elements : libraryServiceApi.listBooks(request)) { - * // doThingsWith(elements); + * for (Book element : libraryServiceApi.listBooks(request)) { + * // doThingsWith(element); * } * } * @@ -1047,8 +1018,8 @@ public class LibraryServiceApi implements AutoCloseable { * .build(); * ListenableFuture<PageAccessor<Book>> future = libraryServiceApi.listBooksPagedCallable().futureCall(request); * // Do something - * for (Book elements : future.get()) { - * // doThingsWith(elements); + * for (Book element : future.get()) { + * // doThingsWith(element); * } * } * @@ -1070,8 +1041,8 @@ public class LibraryServiceApi implements AutoCloseable { * .build(); * while (true) { * ListBooksResponse response = libraryServiceApi.listBooksCallable().call(request); - * for (Book elements : response.getBooksList()) { - * // doThingsWith(elements); + * for (Book element : response.getBooksList()) { + * // doThingsWith(element); * } * String nextPageToken = response.getNextPageToken(); * if (!Strings.isNullOrEmpty(nextPageToken)) { @@ -1087,8 +1058,6 @@ public class LibraryServiceApi implements AutoCloseable { return listBooksCallable; } - // ----- deleteBook ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Deletes a book. @@ -1131,7 +1100,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - private void deleteBook(DeleteBookRequest request) { + private final void deleteBook(DeleteBookRequest request) { deleteBookCallable().call(request); } @@ -1156,8 +1125,6 @@ public class LibraryServiceApi implements AutoCloseable { return deleteBookCallable; } - // ----- updateBook ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Updates a book. @@ -1177,7 +1144,6 @@ public class LibraryServiceApi implements AutoCloseable { */ public final Book updateBook(String name, Book book) { BOOK_PATH_TEMPLATE.validate(name); - UpdateBookRequest request = UpdateBookRequest.newBuilder() .setName(name) @@ -1209,9 +1175,6 @@ public class LibraryServiceApi implements AutoCloseable { */ public final Book updateBook(String name, Book book, FieldMask updateMask, com.google.example.library.v1.FieldMask physicalMask) { BOOK_PATH_TEMPLATE.validate(name); - - - UpdateBookRequest request = UpdateBookRequest.newBuilder() .setName(name) @@ -1242,7 +1205,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - public Book updateBook(UpdateBookRequest request) { + public final Book updateBook(UpdateBookRequest request) { return updateBookCallable().call(request); } @@ -1269,8 +1232,6 @@ public class LibraryServiceApi implements AutoCloseable { return updateBookCallable; } - // ----- moveBook ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Moves a book to another shelf, and returns the new book. @@ -1319,7 +1280,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - public Book moveBook(MoveBookRequest request) { + public final Book moveBook(MoveBookRequest request) { return moveBookCallable().call(request); } @@ -1346,8 +1307,6 @@ public class LibraryServiceApi implements AutoCloseable { return moveBookCallable; } - // ----- listStrings ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Lists a primitive resource. To test go page streaming. @@ -1356,12 +1315,11 @@ public class LibraryServiceApi implements AutoCloseable { *

    * try (LibraryServiceApi libraryServiceApi = LibraryServiceApi.createWithDefaults()) {
    *
-   *   for (String elements : libraryServiceApi.listStrings()) {
-   *     // doThingsWith(elements);
+   *   for (String element : libraryServiceApi.listStrings()) {
+   *     // doThingsWith(element);
    *   }
    * }
    * 
- * * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ public final PageAccessor listStrings() { @@ -1381,8 +1339,8 @@ public class LibraryServiceApi implements AutoCloseable { * try (LibraryServiceApi libraryServiceApi = LibraryServiceApi.createWithDefaults()) { * ListStringsRequest request = ListStringsRequest.newBuilder() * .build(); - * for (String elements : libraryServiceApi.listStrings(request)) { - * // doThingsWith(elements); + * for (String element : libraryServiceApi.listStrings(request)) { + * // doThingsWith(element); * } * } * @@ -1406,8 +1364,8 @@ public class LibraryServiceApi implements AutoCloseable { * .build(); * ListenableFuture<PageAccessor<String>> future = libraryServiceApi.listStringsPagedCallable().futureCall(request); * // Do something - * for (String elements : future.get()) { - * // doThingsWith(elements); + * for (String element : future.get()) { + * // doThingsWith(element); * } * } * @@ -1427,8 +1385,8 @@ public class LibraryServiceApi implements AutoCloseable { * .build(); * while (true) { * ListStringsResponse response = libraryServiceApi.listStringsCallable().call(request); - * for (String elements : response.getStringsList()) { - * // doThingsWith(elements); + * for (String element : response.getStringsList()) { + * // doThingsWith(element); * } * String nextPageToken = response.getNextPageToken(); * if (!Strings.isNullOrEmpty(nextPageToken)) { @@ -1444,8 +1402,6 @@ public class LibraryServiceApi implements AutoCloseable { return listStringsCallable; } - // ----- addComments ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Adds comments to a book @@ -1469,7 +1425,6 @@ public class LibraryServiceApi implements AutoCloseable { */ public final void addComments(String name, List comments) { BOOK_PATH_TEMPLATE.validate(name); - AddCommentsRequest request = AddCommentsRequest.newBuilder() .setName(name) @@ -1502,7 +1457,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - public void addComments(AddCommentsRequest request) { + public final void addComments(AddCommentsRequest request) { addCommentsCallable().call(request); } @@ -1533,8 +1488,6 @@ public class LibraryServiceApi implements AutoCloseable { return addCommentsCallable; } - // ----- getBookFromArchive ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Gets a book from an archive. @@ -1577,7 +1530,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - private Book getBookFromArchive(GetBookFromArchiveRequest request) { + private final Book getBookFromArchive(GetBookFromArchiveRequest request) { return getBookFromArchiveCallable().call(request); } @@ -1602,8 +1555,6 @@ public class LibraryServiceApi implements AutoCloseable { return getBookFromArchiveCallable; } - // ----- updateBookIndex ----- - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Updates the index of a book. @@ -1627,8 +1578,6 @@ public class LibraryServiceApi implements AutoCloseable { */ public final void updateBookIndex(String name, String indexName, Map indexMap) { BOOK_PATH_TEMPLATE.validate(name); - - UpdateBookIndexRequest request = UpdateBookIndexRequest.newBuilder() .setName(name) @@ -1662,7 +1611,7 @@ public class LibraryServiceApi implements AutoCloseable { * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.grpc.ApiException if the remote call fails */ - public void updateBookIndex(UpdateBookIndexRequest request) { + public final void updateBookIndex(UpdateBookIndexRequest request) { updateBookIndexCallable().call(request); } @@ -1693,7 +1642,6 @@ public class LibraryServiceApi implements AutoCloseable { return updateBookIndexCallable; } - /** * Initiates an orderly shutdown in which preexisting calls continue but new calls are immediately * cancelled. diff --git a/src/test/java/com/google/api/codegen/testdata/java_settings_library.baseline b/src/test/java/com/google/api/codegen/testdata/java_settings_library.baseline index 5ffdfc39e5..9d15220668 100644 --- a/src/test/java/com/google/api/codegen/testdata/java_settings_library.baseline +++ b/src/test/java/com/google/api/codegen/testdata/java_settings_library.baseline @@ -64,8 +64,6 @@ import java.util.List; import java.util.concurrent.ScheduledExecutorService; import org.joda.time.Duration; - - // AUTO-GENERATED DOCUMENTATION AND CLASS /** * Settings class to configure an instance of {@link LibraryServiceApi}. @@ -81,13 +79,13 @@ import org.joda.time.Duration; * *

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 CreateShelf to 30 seconds: + * object. For example, to set the total timeout of createShelf to 30 seconds: * *

  * 
  * LibraryServiceSettings.Builder libraryServiceSettingsBuilder =
  *     LibraryServiceSettings.defaultBuilder();
- * libraryServiceSettingsBuilder.CreateShelfSettings().getRetrySettingsBuilder()
+ * libraryServiceSettingsBuilder.createShelfSettings().getRetrySettingsBuilder()
  *     .setTotalTimeout(Duration.standardSeconds(30));
  * LibraryServiceSettings libraryServiceSettings = libraryServiceSettingsBuilder.build();
  * 
@@ -95,7 +93,6 @@ import org.joda.time.Duration;
  */
 @javax.annotation.Generated("by GAPIC")
 public class LibraryServiceSettings extends ServiceApiSettings {
-
   /**
    * The default address of the service.
    */
@@ -110,8 +107,8 @@ public class LibraryServiceSettings extends ServiceApiSettings {
    * The default scopes of the service.
    */
   public static final ImmutableList DEFAULT_SERVICE_SCOPES = ImmutableList.builder()
-      .add("https://www.googleapis.com/auth/library")
       .add("https://www.googleapis.com/auth/cloud-platform")
+      .add("https://www.googleapis.com/auth/library")
       .build();
 
   /**
@@ -126,23 +123,17 @@ public class LibraryServiceSettings extends ServiceApiSettings {
 
   private final SimpleCallSettings createShelfSettings;
   private final SimpleCallSettings getShelfSettings;
-  private final PageStreamingCallSettings
-      listShelvesSettings;
-
+  private final PageStreamingCallSettings listShelvesSettings;
   private final SimpleCallSettings deleteShelfSettings;
   private final SimpleCallSettings mergeShelvesSettings;
   private final SimpleCallSettings createBookSettings;
   private final BundlingCallSettings publishSeriesSettings;
   private final SimpleCallSettings getBookSettings;
-  private final PageStreamingCallSettings
-      listBooksSettings;
-
+  private final PageStreamingCallSettings listBooksSettings;
   private final SimpleCallSettings deleteBookSettings;
   private final SimpleCallSettings updateBookSettings;
   private final SimpleCallSettings moveBookSettings;
-  private final PageStreamingCallSettings
-      listStringsSettings;
-
+  private final PageStreamingCallSettings listStringsSettings;
   private final SimpleCallSettings addCommentsSettings;
   private final SimpleCallSettings getBookFromArchiveSettings;
   private final SimpleCallSettings updateBookIndexSettings;
@@ -164,8 +155,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
   /**
    * Returns the object with the settings used for calls to listShelves.
    */
-  public PageStreamingCallSettings
-      listShelvesSettings() {
+  public PageStreamingCallSettings listShelvesSettings() {
     return listShelvesSettings;
   }
 
@@ -207,8 +197,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
   /**
    * Returns the object with the settings used for calls to listBooks.
    */
-  public PageStreamingCallSettings
-      listBooksSettings() {
+  public PageStreamingCallSettings listBooksSettings() {
     return listBooksSettings;
   }
 
@@ -236,8 +225,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
   /**
    * Returns the object with the settings used for calls to listStrings.
    */
-  public PageStreamingCallSettings
-      listStringsSettings() {
+  public PageStreamingCallSettings listStringsSettings() {
     return listStringsSettings;
   }
 
@@ -262,7 +250,6 @@ public class LibraryServiceSettings extends ServiceApiSettings {
     return updateBookIndexSettings;
   }
 
-
   /**
    * Returns a builder for this class with recommended defaults.
    */
@@ -317,8 +304,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
           return "";
         }
         @Override
-        public ListShelvesRequest injectToken(
-            ListShelvesRequest payload, Object token) {
+        public ListShelvesRequest injectToken(ListShelvesRequest payload, Object token) {
           return ListShelvesRequest
             .newBuilder(payload)
             .setPageToken((String) token)
@@ -341,8 +327,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
           return "";
         }
         @Override
-        public ListBooksRequest injectToken(
-            ListBooksRequest payload, Object token) {
+        public ListBooksRequest injectToken(ListBooksRequest payload, Object token) {
           return ListBooksRequest
             .newBuilder(payload)
             .setPageToken((String) token)
@@ -365,8 +350,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
           return "";
         }
         @Override
-        public ListStringsRequest injectToken(
-            ListStringsRequest payload, Object token) {
+        public ListStringsRequest injectToken(ListStringsRequest payload, Object token) {
           return ListStringsRequest
             .newBuilder(payload)
             .setPageToken((String) token)
@@ -386,7 +370,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
       new BundlingDescriptor() {
         @Override
         public String getBundlePartitionKey(PublishSeriesRequest request) {
-          return request.getEdition() + "|" + request.getName();
+          return request.getEdition() + "|" + request.getName() + "|";
         }
 
         @Override
@@ -445,7 +429,6 @@ public class LibraryServiceSettings extends ServiceApiSettings {
         }
       };
 
-
   /**
    * Builder for LibraryServiceSettings.
    */
@@ -454,20 +437,17 @@ public class LibraryServiceSettings extends ServiceApiSettings {
 
     private SimpleCallSettings.Builder createShelfSettings;
     private SimpleCallSettings.Builder getShelfSettings;
-    private PageStreamingCallSettings.Builder
-        listShelvesSettings;
+    private PageStreamingCallSettings.Builder listShelvesSettings;
     private SimpleCallSettings.Builder deleteShelfSettings;
     private SimpleCallSettings.Builder mergeShelvesSettings;
     private SimpleCallSettings.Builder createBookSettings;
     private BundlingCallSettings.Builder publishSeriesSettings;
     private SimpleCallSettings.Builder getBookSettings;
-    private PageStreamingCallSettings.Builder
-        listBooksSettings;
+    private PageStreamingCallSettings.Builder listBooksSettings;
     private SimpleCallSettings.Builder deleteBookSettings;
     private SimpleCallSettings.Builder updateBookSettings;
     private SimpleCallSettings.Builder moveBookSettings;
-    private PageStreamingCallSettings.Builder
-        listStringsSettings;
+    private PageStreamingCallSettings.Builder listStringsSettings;
     private SimpleCallSettings.Builder addCommentsSettings;
     private SimpleCallSettings.Builder getBookFromArchiveSettings;
     private SimpleCallSettings.Builder updateBookIndexSettings;
@@ -568,6 +548,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
 
     private static Builder createDefault() {
       Builder builder = new Builder();
+
       builder.createShelfSettings()
           .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent"))
           .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
@@ -577,8 +558,8 @@ public class LibraryServiceSettings extends ServiceApiSettings {
           .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
 
       builder.listShelvesSettings()
-              .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
-              .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
+          .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
+          .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
 
       builder.deleteShelfSettings()
           .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
@@ -593,23 +574,23 @@ public class LibraryServiceSettings extends ServiceApiSettings {
           .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
 
       builder.publishSeriesSettings().getBundlingSettingsBuilder()
-              .setElementCountThreshold(6)
-              .setElementCountLimit(7)
-              .setRequestByteThreshold(100000)
-              .setRequestByteLimit(150000)
-              .setDelayThreshold(Duration.millis(500))
-              .setBlockingCallCountThreshold(1);
+          .setElementCountThreshold(6)
+          .setElementCountLimit(7)
+          .setRequestByteThreshold(100000)
+          .setRequestByteLimit(150000)
+          .setDelayThreshold(Duration.millis(500))
+          .setBlockingCallCountThreshold(1);
       builder.publishSeriesSettings()
-              .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent"))
-              .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
+          .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent"))
+          .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
 
       builder.getBookSettings()
           .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
           .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
 
       builder.listBooksSettings()
-              .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
-              .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
+          .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
+          .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
 
       builder.deleteBookSettings()
           .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
@@ -624,8 +605,8 @@ public class LibraryServiceSettings extends ServiceApiSettings {
           .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
 
       builder.listStringsSettings()
-              .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
-              .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
+          .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
+          .setRetrySettingsBuilder(RETRY_PARAM_DEFINITIONS.get("default"));
 
       builder.addCommentsSettings()
           .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent"))
@@ -749,8 +730,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
     /**
      * Returns the builder for the settings used for calls to listShelves.
      */
-    public PageStreamingCallSettings.Builder
-        listShelvesSettings() {
+    public PageStreamingCallSettings.Builder listShelvesSettings() {
       return listShelvesSettings;
     }
 
@@ -792,8 +772,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
     /**
      * Returns the builder for the settings used for calls to listBooks.
      */
-    public PageStreamingCallSettings.Builder
-        listBooksSettings() {
+    public PageStreamingCallSettings.Builder listBooksSettings() {
       return listBooksSettings;
     }
 
@@ -821,8 +800,7 @@ public class LibraryServiceSettings extends ServiceApiSettings {
     /**
      * Returns the builder for the settings used for calls to listStrings.
      */
-    public PageStreamingCallSettings.Builder
-        listStringsSettings() {
+    public PageStreamingCallSettings.Builder listStringsSettings() {
       return listStringsSettings;
     }
 
diff --git a/src/test/java/com/google/api/codegen/testdata/nodejs_main_library.baseline b/src/test/java/com/google/api/codegen/testdata/nodejs_main_library.baseline
index 907a8ae3f7..00ed0f8842 100644
--- a/src/test/java/com/google/api/codegen/testdata/nodejs_main_library.baseline
+++ b/src/test/java/com/google/api/codegen/testdata/nodejs_main_library.baseline
@@ -74,8 +74,8 @@ var BUNDLE_DESCRIPTORS = {
  * this service.
  */
 var ALL_SCOPES = [
-  'https://www.googleapis.com/auth/library',
-  'https://www.googleapis.com/auth/cloud-platform'
+  'https://www.googleapis.com/auth/cloud-platform',
+  'https://www.googleapis.com/auth/library'
 ];
 
 /**
diff --git a/src/test/java/com/google/api/codegen/testdata/php_main_library.baseline b/src/test/java/com/google/api/codegen/testdata/php_main_library.baseline
index 56b1a831b4..964d736901 100644
--- a/src/test/java/com/google/api/codegen/testdata/php_main_library.baseline
+++ b/src/test/java/com/google/api/codegen/testdata/php_main_library.baseline
@@ -42,15 +42,11 @@ use google\example\library\v1\GetBookRequest;
 use google\example\library\v1\GetShelfRequest;
 use google\example\library\v1\LibraryServiceClient;
 use google\example\library\v1\ListBooksRequest;
-use google\example\library\v1\ListBooksResponse;
 use google\example\library\v1\ListShelvesRequest;
-use google\example\library\v1\ListShelvesResponse;
 use google\example\library\v1\ListStringsRequest;
-use google\example\library\v1\ListStringsResponse;
 use google\example\library\v1\MergeShelvesRequest;
 use google\example\library\v1\MoveBookRequest;
 use google\example\library\v1\PublishSeriesRequest;
-use google\example\library\v1\PublishSeriesResponse;
 use google\example\library\v1\Shelf;
 use google\example\library\v1\SomeMessage;
 use google\example\library\v1\StringBuilder;
@@ -142,7 +138,8 @@ class LibraryServiceApi
     public static function formatBookName($shelf, $book)
     {
         return self::getBookNameTemplate()->render([
-            'shelf' => $shelf, 'book' => $book,
+            'shelf' => $shelf,
+            'book' => $book,
         ]);
     }
 
@@ -153,7 +150,8 @@ class LibraryServiceApi
     public static function formatArchivedBookName($archivePath, $book)
     {
         return self::getArchivedBookNameTemplate()->render([
-            'archive_path' => $archivePath, 'book' => $book,
+            'archive_path' => $archivePath,
+            'book' => $book,
         ]);
     }
 
@@ -293,8 +291,8 @@ class LibraryServiceApi
     public function __construct($options = [])
     {
         $defaultScopes = [
-            'https://www.googleapis.com/auth/library',
             'https://www.googleapis.com/auth/cloud-platform',
+            'https://www.googleapis.com/auth/library',
         ];
         $defaultOptions = [
             'serviceAddress' => self::SERVICE_ADDRESS,
@@ -341,6 +339,7 @@ class LibraryServiceApi
         }
 
         // TODO load the client config in a more package-friendly way
+        // https://github.com/googleapis/toolkit/issues/332
         $clientConfigJsonString = file_get_contents('./resources/library_service_client_config.json');
         $clientConfig = json_decode($clientConfigJsonString, true);
         $this->defaultCallSettings =
@@ -389,11 +388,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -439,15 +438,16 @@ class LibraryServiceApi
      * @param string $options To test 'options' parameter name conflict.
      * @param array $optionalArgs {
      *     Optional.
-     *     @var SomeMessage $message Field to verify that message-type query parameter gets flattened.
+     *     @var SomeMessage $message
+     *          Field to verify that message-type query parameter gets flattened.
      *     @var StringBuilder $stringBuilder
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -502,11 +502,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -552,11 +552,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -605,11 +605,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -659,11 +659,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -710,14 +710,15 @@ class LibraryServiceApi
      * @param Book[] $books The books to publish in the series.
      * @param array $optionalArgs {
      *     Optional.
-     *     @var int $edition The edition of the series
+     *     @var int $edition
+     *          The edition of the series
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -770,11 +771,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -821,19 +822,20 @@ class LibraryServiceApi
      * @param array $optionalArgs {
      *     Optional.
      *     @var int $pageSize
-     *           The maximum number of resources contained in the underlying API
-     *           response. If page streaming is performed per-resource, this
-     *           parameter does not affect the return value. If page streaming is
-     *           performed per-page, this determines the maximum number of
-     *           resources in a page.
-     *     @var string $filter To test python built-in wrapping.
+     *          The maximum number of resources contained in the underlying API
+     *          response. If page streaming is performed per-resource, this
+     *          parameter does not affect the return value. If page streaming is
+     *          performed per-page, this determines the maximum number of
+     *          resources in a page.
+     *     @var string $filter
+     *          To test python built-in wrapping.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -886,11 +888,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -934,15 +936,17 @@ class LibraryServiceApi
      * @param Book $book The book to update with.
      * @param array $optionalArgs {
      *     Optional.
-     *     @var FieldMask $updateMask A field mask to apply, rendered as an HTTP parameter.
-     *     @var google\example\library\v1\FieldMask $physicalMask To test Python import clash resolution.
+     *     @var FieldMask $updateMask
+     *          A field mask to apply, rendered as an HTTP parameter.
+     *     @var google\example\library\v1\FieldMask $physicalMask
+     *          To test Python import clash resolution.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -998,11 +1002,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -1050,18 +1054,18 @@ class LibraryServiceApi
      *     Optional.
      *     @var string $name
      *     @var int $pageSize
-     *           The maximum number of resources contained in the underlying API
-     *           response. If page streaming is performed per-resource, this
-     *           parameter does not affect the return value. If page streaming is
-     *           performed per-page, this determines the maximum number of
-     *           resources in a page.
+     *          The maximum number of resources contained in the underlying API
+     *          response. If page streaming is performed per-resource, this
+     *          parameter does not affect the return value. If page streaming is
+     *          performed per-page, this determines the maximum number of
+     *          resources in a page.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -1118,11 +1122,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -1170,11 +1174,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -1207,7 +1211,7 @@ class LibraryServiceApi
      * try {
      *     $libraryServiceApi = new LibraryServiceApi();
      *     $formattedName = LibraryServiceApi::formatBookName("[SHELF]", "[BOOK]");
-     *     $indexName = "";
+     *     $indexName = "default index";
      *     $indexMapItem = "";
      *     $indexMap = ["default_key" => $indexMapItem,];
      *     $libraryServiceApi->updateBookIndex($formattedName, $indexName, $indexMap);
@@ -1226,11 +1230,11 @@ class LibraryServiceApi
      *               this $optionalArgs parameter reserves a spot for future ones.
      * }
      * @param array $callSettings {
-     *    Optional.
-     *    @var Google\GAX\RetrySettings $retrySettings
+     *     Optional.
+     *     @var Google\GAX\RetrySettings $retrySettings
      *          Retry settings to use for this call. If present, then
-     *          $timeout is ignored.
-     *    @var int $timeoutMillis
+     *          $timeoutMillis is ignored.
+     *     @var int $timeoutMillis
      *          Timeout to use for this call. Only used if $retrySettings
      *          is not set.
      * }
@@ -1271,4 +1275,3 @@ class LibraryServiceApi
         return $this->grpcBootstrap->createCallCredentialsCallback($this->scopes);
     }
 }
-
diff --git a/src/test/java/com/google/api/codegen/testdata/python_main_library.baseline b/src/test/java/com/google/api/codegen/testdata/python_main_library.baseline
index 8636aa7692..08561b4125 100644
--- a/src/test/java/com/google/api/codegen/testdata/python_main_library.baseline
+++ b/src/test/java/com/google/api/codegen/testdata/python_main_library.baseline
@@ -103,8 +103,8 @@ class LibraryServiceApi(object):
     # The scopes needed to make gRPC calls to all of the methods defined in
     # this service
     _ALL_SCOPES = (
-        'https://www.googleapis.com/auth/library',
         'https://www.googleapis.com/auth/cloud-platform',
+        'https://www.googleapis.com/auth/library',
     )
 
     _SHELF_PATH_TEMPLATE = path_template.PathTemplate(
diff --git a/src/test/java/com/google/api/codegen/testdata/ruby_main_library.baseline b/src/test/java/com/google/api/codegen/testdata/ruby_main_library.baseline
index cb230c3c22..83ce4b998b 100644
--- a/src/test/java/com/google/api/codegen/testdata/ruby_main_library.baseline
+++ b/src/test/java/com/google/api/codegen/testdata/ruby_main_library.baseline
@@ -91,8 +91,8 @@ module Library
       # The scopes needed to make gRPC calls to all of the methods defined in
       # this service.
       ALL_SCOPES = [
-        'https://www.googleapis.com/auth/library',
-        'https://www.googleapis.com/auth/cloud-platform'
+        'https://www.googleapis.com/auth/cloud-platform',
+        'https://www.googleapis.com/auth/library'
       ].freeze
 
       SHELF_PATH_TEMPLATE = Google::Gax::PathTemplate.new(
diff --git a/src/test/java/com/google/api/codegen/util/NamePathTest.java b/src/test/java/com/google/api/codegen/util/NamePathTest.java
new file mode 100644
index 0000000000..53feaaae47
--- /dev/null
+++ b/src/test/java/com/google/api/codegen/util/NamePathTest.java
@@ -0,0 +1,40 @@
+/* Copyright 2016 Google Inc
+ *
+ * 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
+ *
+ *      http://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.util;
+
+import com.google.common.truth.Truth;
+
+import org.junit.Test;
+
+public class NamePathTest {
+
+  @Test
+  public void testSingleWord() {
+    NamePath path = NamePath.dotted("Foo");
+    Truth.assertThat(path.toDotted()).isEqualTo("Foo");
+    Truth.assertThat(path.toBackslashed()).isEqualTo("Foo");
+    Truth.assertThat(path.getHead()).isEqualTo("Foo");
+    Truth.assertThat(path.withHead("Bar").toDotted()).isEqualTo("Bar");
+  }
+
+  @Test
+  public void testDottedPath() {
+    NamePath path = NamePath.dotted("com.google.Foo");
+    Truth.assertThat(path.toDotted()).isEqualTo("com.google.Foo");
+    Truth.assertThat(path.toBackslashed()).isEqualTo("com\\google\\Foo");
+    Truth.assertThat(path.getHead()).isEqualTo("Foo");
+    Truth.assertThat(path.withHead("Bar").toDotted()).isEqualTo("com.google.Bar");
+  }
+}
diff --git a/src/test/java/com/google/api/codegen/util/NameTest.java b/src/test/java/com/google/api/codegen/util/NameTest.java
new file mode 100644
index 0000000000..b2992584d9
--- /dev/null
+++ b/src/test/java/com/google/api/codegen/util/NameTest.java
@@ -0,0 +1,96 @@
+/* Copyright 2016 Google Inc
+ *
+ * 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
+ *
+ *      http://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.util;
+
+import com.google.common.truth.Truth;
+
+import org.junit.Test;
+
+public class NameTest {
+
+  @Test
+  public void testEmpty() {
+    Name name = Name.from();
+    Truth.assertThat(name.toLowerUnderscore()).isEqualTo("");
+    Truth.assertThat(name.toUpperUnderscore()).isEqualTo("");
+    Truth.assertThat(name.toLowerCamel()).isEqualTo("");
+    Truth.assertThat(name.toUpperCamel()).isEqualTo("");
+  }
+
+  @Test
+  public void testSingleWord() {
+    Name name = Name.from("dog");
+    Truth.assertThat(name.toLowerUnderscore()).isEqualTo("dog");
+    Truth.assertThat(name.toUpperUnderscore()).isEqualTo("DOG");
+    Truth.assertThat(name.toLowerCamel()).isEqualTo("dog");
+    Truth.assertThat(name.toUpperCamel()).isEqualTo("Dog");
+  }
+
+  @Test
+  public void testMultipleWords() {
+    Name name = Name.from("factory_decorator", "delegate_impl");
+    Truth.assertThat(name.toLowerUnderscore()).isEqualTo("factory_decorator_delegate_impl");
+    Truth.assertThat(name.toUpperUnderscore()).isEqualTo("FACTORY_DECORATOR_DELEGATE_IMPL");
+    Truth.assertThat(name.toLowerCamel()).isEqualTo("factoryDecoratorDelegateImpl");
+    Truth.assertThat(name.toUpperCamel()).isEqualTo("FactoryDecoratorDelegateImpl");
+  }
+
+  @Test
+  public void testFromLowerCamel() {
+    Name name = Name.lowerCamel("factoryDecorator", "delegateImpl");
+    Truth.assertThat(name.toLowerUnderscore()).isEqualTo("factory_decorator_delegate_impl");
+    Truth.assertThat(name.toUpperUnderscore()).isEqualTo("FACTORY_DECORATOR_DELEGATE_IMPL");
+    Truth.assertThat(name.toLowerCamel()).isEqualTo("factoryDecoratorDelegateImpl");
+    Truth.assertThat(name.toUpperCamel()).isEqualTo("FactoryDecoratorDelegateImpl");
+  }
+
+  @Test
+  public void testFromUpperCamel() {
+    Name name = Name.upperCamel("FactoryDecorator", "DelegateImpl");
+    Truth.assertThat(name.toLowerUnderscore()).isEqualTo("factory_decorator_delegate_impl");
+    Truth.assertThat(name.toUpperUnderscore()).isEqualTo("FACTORY_DECORATOR_DELEGATE_IMPL");
+    Truth.assertThat(name.toLowerCamel()).isEqualTo("factoryDecoratorDelegateImpl");
+    Truth.assertThat(name.toUpperCamel()).isEqualTo("FactoryDecoratorDelegateImpl");
+  }
+
+  @Test
+  public void testWordAndNumber() {
+    Name name = Name.from("dog", "2");
+    Truth.assertThat(name.toLowerUnderscore()).isEqualTo("dog_2");
+    Truth.assertThat(name.toUpperUnderscore()).isEqualTo("DOG_2");
+    Truth.assertThat(name.toLowerCamel()).isEqualTo("dog2");
+    Truth.assertThat(name.toUpperCamel()).isEqualTo("Dog2");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void illegalLowerUnderscore() {
+    Name.from("factoryDecorator");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void illegalUpperUnderscore() {
+    Name.upperCamel("factory_decorator");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void illegalLowerCamel() {
+    Name.lowerCamel("FactoryDecorator");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void illegalUpperCamel() {
+    Name.upperCamel("factoryDecorator");
+  }
+}
diff --git a/src/test/java/com/google/api/codegen/util/TypeNameTest.java b/src/test/java/com/google/api/codegen/util/TypeNameTest.java
new file mode 100644
index 0000000000..ad64ee689d
--- /dev/null
+++ b/src/test/java/com/google/api/codegen/util/TypeNameTest.java
@@ -0,0 +1,99 @@
+/* Copyright 2016 Google Inc
+ *
+ * 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
+ *
+ *      http://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.util;
+
+import com.google.common.truth.Truth;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+public class TypeNameTest {
+
+  @Test
+  public void testSimple() {
+    TypeName typeName = new TypeName("com.google.Foo", "Foo");
+    Truth.assertThat(typeName.getFullName()).isEqualTo("com.google.Foo");
+    Truth.assertThat(typeName.getNickname()).isEqualTo("Foo");
+    MockTypeTable typeTable = new MockTypeTable();
+    Truth.assertThat(typeName.getAndSaveNicknameIn(typeTable)).isEqualTo("Foo");
+    List expectedImports = Arrays.asList(TypeAlias.create("com.google.Foo", "Foo"));
+    Truth.assertThat(typeTable.imports).isEqualTo(expectedImports);
+  }
+
+  @Test
+  public void testComposite() {
+    TypeName typeName = new TypeName("com.google.Foo", "Foo");
+    TypeName containerTypeName =
+        new TypeName("com.google.Container", "Container", "%s<%i>", typeName);
+    Truth.assertThat(containerTypeName.getFullName())
+        .isEqualTo("com.google.Container");
+    Truth.assertThat(containerTypeName.getNickname()).isEqualTo("Container");
+    MockTypeTable typeTable = new MockTypeTable();
+    Truth.assertThat(containerTypeName.getAndSaveNicknameIn(typeTable)).isEqualTo("Container");
+    List expectedImports =
+        Arrays.asList(
+            TypeAlias.create("com.google.Container", "Container"),
+            TypeAlias.create("com.google.Foo", "Foo"));
+    Truth.assertThat(typeTable.imports).isEqualTo(expectedImports);
+  }
+
+  private static class MockTypeTable implements TypeTable {
+    public List imports = new ArrayList<>();
+
+    @Override
+    public String getAndSaveNicknameFor(TypeAlias alias) {
+      imports.add(alias);
+      return alias.getNickname();
+    }
+
+    @Override
+    public TypeName getTypeName(String fullName) {
+      return null;
+    }
+
+    @Override
+    public TypeTable cloneEmpty() {
+      return new MockTypeTable();
+    }
+
+    @Override
+    public String getAndSaveNicknameFor(String fullName) {
+      return null;
+    }
+
+    @Override
+    public String getAndSaveNicknameFor(TypeName typeName) {
+      return null;
+    }
+
+    @Override
+    public List getImports() {
+      return null;
+    }
+
+    @Override
+    public NamePath getNamePath(String fullName) {
+      return null;
+    }
+
+    @Override
+    public TypeName getContainerTypeName(String containerFullName, String elementFullName) {
+      return null;
+    }
+  }
+}