diff --git a/.gitignore b/.gitignore index 565e7ae9fb..b796b11f6e 100644 --- a/.gitignore +++ b/.gitignore @@ -289,4 +289,7 @@ __pycache__/ package-lock.json *.class -test/*/target/ \ No newline at end of file +test/*/target/ +.settings/ +.project +.classpath \ No newline at end of file diff --git a/src/azure/Model/CodeModelJva.cs b/src/azure/Model/CodeModelJva.cs index c21b0169cf..63d5c99031 100644 --- a/src/azure/Model/CodeModelJva.cs +++ b/src/azure/Model/CodeModelJva.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. using System.Collections.Generic; @@ -8,6 +8,8 @@ using AutoRest.Java.Model; using AutoRest.Core.Utilities.Collections; using Newtonsoft.Json; +using System.Text.RegularExpressions; +using AutoRest.Core; namespace AutoRest.Java.Azure.Model { @@ -64,5 +66,61 @@ public string SetDefaultHeaders return ""; } } + + /// + /// Attempts to infer the name of the service referenced by this CodeModel. + /// + [JsonIgnore] + public string ServiceName + { + get + { + var serviceNameSetting = Settings.Instance.Host?.GetValue("service-name").Result; + if (!string.IsNullOrEmpty(serviceNameSetting)) + { + return serviceNameSetting; + } + + var method = Methods[0]; + var match = Regex.Match(input: method.Url, pattern: @"/providers/microsoft\.(\w+)/", options: RegexOptions.IgnoreCase); + var serviceName = match.Groups[1].Value.ToPascalCase(); + return serviceName; + } + } + + + const string targetVersion = "1.1.3"; + /// + /// The Azure SDK version to reference in the generated POM. + /// + [JsonIgnore] + public string PomVersion + { + get + { + return targetVersion + "-SNAPSHOT"; + } + } + + /// + /// The Beta.SinceVersion value to pass to the Beta annotation. + /// + [JsonIgnore] + public string BetaSinceVersion + { + get + { + var versionParts = targetVersion.Split('.'); + var minorVersion = int.Parse(versionParts[1]); + var patchVersion = int.Parse(versionParts[2]); + + var newMinorVersion = patchVersion == 0 + ? minorVersion + : minorVersion + 1; + + var result = "V" + versionParts[0] + "_" + newMinorVersion + "_0"; + return result; + } + } } -} \ No newline at end of file +} diff --git a/src/azure/Templates/AzurePomTemplate.cshtml b/src/azure/Templates/AzurePomTemplate.cshtml new file mode 100644 index 0000000000..6ce1102091 --- /dev/null +++ b/src/azure/Templates/AzurePomTemplate.cshtml @@ -0,0 +1,136 @@ +@using System +@using System.Linq; +@using AutoRest.Java +@using AutoRest.Java.Model +@using AutoRest.Java.Azure.Model +@inherits AutoRest.Core.Template +@{ + var serviceName = Model.ServiceName; +} + + + 4.0.0 + + com.microsoft.azure + azure-parent + @Model.PomVersion + ../pom.xml + + + azure-mgmt-@serviceName.ToLower() + jar + + Microsoft Azure SDK for @serviceName Management + This package contains Microsoft @serviceName Management SDK. + https://github.com/Azure/azure-sdk-for-java + + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + repo + + + + + scm:git:https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + + UTF-8 + + + + + + microsoft + Microsoft + + + + + + com.microsoft.azure + azure-client-runtime + + + com.microsoft.azure + azure-mgmt-resources + @Model.PomVersion + + + junit + junit + test + + + com.microsoft.azure + azure-client-authentication + test + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + true + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + com.microsoft.azure.management.apigeneration.LangDefinitionProcessor + + + true + true + + true + true + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.8 + + *.implementation.*;*.utils.*;com.microsoft.schemas._2003._10.serialization;*.blob.core.search + + + /** +
* Copyright (c) Microsoft Corporation. All rights reserved. +
* Licensed under the MIT License. See License.txt in the project root for +
* license information. +
*/ + ]]> +
+
+
+ +
+
+
diff --git a/src/azure/Templates/AzureServiceManagerTemplate.cshtml b/src/azure/Templates/AzureServiceManagerTemplate.cshtml new file mode 100644 index 0000000000..2e6a85caae --- /dev/null +++ b/src/azure/Templates/AzureServiceManagerTemplate.cshtml @@ -0,0 +1,107 @@ +@using System +@using System.Text.RegularExpressions +@using System.Linq +@using AutoRest.Core.Utilities +@using AutoRest.Java +@using AutoRest.Java.Azure.Model +@using AutoRest.Java.Model +@inherits AutoRest.Core.Template + +@{ + var serviceName = Model.ServiceName; + var className = serviceName + "Manager"; +} + +/** +@Header(" * ").TrimMultilineHeader() + */ +@EmptyLine + +package @(Settings.Namespace.ToLower()).@(Model.ImplPackage); + +@EmptyLine +import com.microsoft.azure.AzureEnvironment; +import com.microsoft.azure.AzureResponseBuilder; +import com.microsoft.azure.credentials.AzureTokenCredentials; +import com.microsoft.azure.management.apigeneration.Beta; +import com.microsoft.azure.management.apigeneration.Beta.SinceVersion; +import com.microsoft.azure.management.resources.fluentcore.arm.AzureConfigurable; +import com.microsoft.azure.management.resources.fluentcore.arm.implementation.AzureConfigurableImpl; +import com.microsoft.azure.management.resources.fluentcore.arm.implementation.Manager; +import com.microsoft.azure.management.resources.fluentcore.utils.ProviderRegistrationInterceptor; +import com.microsoft.azure.serializer.AzureJacksonAdapter; +import com.microsoft.rest.RestClient; +@EmptyLine + +/** + * Entry point to Azure @(serviceName) resource management. + */ +@@Beta(SinceVersion.@Model.BetaSinceVersion) +public final class @(className) extends Manager<@(className), @(Model.Name + "Impl")> { + /** + * Get a Configurable instance that can be used to create @(className) with optional configuration. + * + * @@return the instance allowing configurations + */ + public static Configurable configure() { + return new @(className).ConfigurableImpl(); + } + + /** + * Creates an instance of @className that exposes @serviceName resource management API entry points. + * + * @@param credentials the credentials to use + * @@param subscriptionId the subscription UUID + * @@return the @className + */ + public static @className authenticate(AzureTokenCredentials credentials, String subscriptionId) { + return new @(className)(new RestClient.Builder() + .withBaseUrl(credentials.environment(), AzureEnvironment.Endpoint.RESOURCE_MANAGER) + .withCredentials(credentials) + .withSerializerAdapter(new AzureJacksonAdapter()) + .withResponseBuilderFactory(new AzureResponseBuilder.Factory()) + .withInterceptor(new ProviderRegistrationInterceptor(credentials)) + .build(), subscriptionId); + } + + /** + * Creates an instance of @className that exposes @serviceName resource management API entry points. + * + * @@param restClient the RestClient to be used for API calls. + * @@param subscriptionId the subscription UUID + * @@return the @className + */ + public static @className authenticate(RestClient restClient, String subscriptionId) { + return new @(className)(restClient, subscriptionId); + } + + /** + * The interface allowing configurations to be set. + */ + public interface Configurable extends AzureConfigurable { + /** + * Creates an instance of @className that exposes @serviceName management API entry points. + * + * @@param credentials the credentials to use + * @@param subscriptionId the subscription UUID + * @@return the interface exposing @serviceName management API entry points that work across subscriptions + */ + @className authenticate(AzureTokenCredentials credentials, String subscriptionId); + } + + /** + * The implementation for Configurable interface. + */ + private static final class ConfigurableImpl extends AzureConfigurableImpl implements Configurable { + public @className authenticate(AzureTokenCredentials credentials, String subscriptionId) { + return @(className).authenticate(buildRestClient(credentials), subscriptionId); + } + } + + private @(className)(RestClient restClient, String subscriptionId) { + super( + restClient, + subscriptionId, + new @(Model.Name)Impl(restClient).withSubscriptionId(subscriptionId)); + } +} diff --git a/src/azurefluent/CodeGeneratorJvaf.cs b/src/azurefluent/CodeGeneratorJvaf.cs index 9c218afeef..494ff2e9eb 100644 --- a/src/azurefluent/CodeGeneratorJvaf.cs +++ b/src/azurefluent/CodeGeneratorJvaf.cs @@ -16,6 +16,7 @@ using AutoRest.Java.Model; using AutoRest.Java.vanilla.Templates; using System; +using System.Text.RegularExpressions; namespace AutoRest.Java.Azure.Fluent { @@ -35,6 +36,8 @@ public class CodeGeneratorJvaf : CodeGeneratorJva /// public override async Task Generate(CodeModel cm) { + var packagePath = Path.Combine("src/main/java", cm.Namespace.ToLower().Replace('.', '/')); + // get Azure Java specific codeModel var codeModel = cm as CodeModelJvaf; if (codeModel == null) @@ -44,14 +47,14 @@ public override async Task Generate(CodeModel cm) // Service client var serviceClientTemplate = new AzureServiceClientTemplate { Model = codeModel }; - await Write(serviceClientTemplate, $"{Path.Combine("implementation", codeModel.Name.ToPascalCase() + "Impl")}{ImplementationFileExtension}"); + await Write(serviceClientTemplate, Path.Combine(packagePath, "implementation", codeModel.Name.ToPascalCase() + "Impl" + ImplementationFileExtension)); // operations foreach (MethodGroupJvaf methodGroup in codeModel.AllOperations) { // Operation var operationsTemplate = new AzureMethodGroupTemplate { Model = methodGroup }; - await Write(operationsTemplate, $"{Path.Combine("implementation", methodGroup.TypeName.ToPascalCase())}Inner{ImplementationFileExtension}"); + await Write(operationsTemplate, Path.Combine(packagePath, "implementation", methodGroup.TypeName.ToPascalCase()) + "Inner" + ImplementationFileExtension); } //Models @@ -68,14 +71,14 @@ public override async Task Generate(CodeModel cm) } var modelTemplate = new ModelTemplate { Model = modelType }; - await Write(modelTemplate, Path.Combine(modelType.ModelsPackage.Trim('.'), $"{modelType.Name.ToPascalCase()}{ImplementationFileExtension}")); + await Write(modelTemplate, Path.Combine(packagePath, modelType.ModelsPackage.Trim('.'), $"{modelType.Name.ToPascalCase()}{ImplementationFileExtension}")); } //Enums foreach (EnumTypeJvaf enumType in cm.EnumTypes) { var enumTemplate = new EnumTemplate { Model = enumType }; - await Write(enumTemplate, Path.Combine(enumType.ModelsPackage.Trim('.'), $"{enumTemplate.Model.Name.ToPascalCase()}{ImplementationFileExtension}")); + await Write(enumTemplate, Path.Combine(packagePath, enumType.ModelsPackage.Trim('.'), $"{enumTemplate.Model.Name.ToPascalCase()}{ImplementationFileExtension}")); } // Page class @@ -85,7 +88,7 @@ public override async Task Generate(CodeModel cm) { Model = new PageJvaf(pageClass.Value, pageClass.Key.Key, pageClass.Key.Value), }; - await Write(pageTemplate, Path.Combine("implementation", $"{pageTemplate.Model.TypeDefinitionName.ToPascalCase()}{ImplementationFileExtension}")); + await Write(pageTemplate, Path.Combine(packagePath, "implementation", $"{pageTemplate.Model.TypeDefinitionName.ToPascalCase()}{ImplementationFileExtension}")); } // Exceptions @@ -97,18 +100,29 @@ public override async Task Generate(CodeModel cm) } var exceptionTemplate = new ExceptionTemplate { Model = exceptionType }; - await Write(exceptionTemplate, Path.Combine(exceptionType.ModelsPackage.Trim('.'), $"{exceptionTemplate.Model.ExceptionTypeDefinitionName}{ImplementationFileExtension}")); + await Write(exceptionTemplate, Path.Combine(packagePath, exceptionType.ModelsPackage.Trim('.'), $"{exceptionTemplate.Model.ExceptionTypeDefinitionName}{ImplementationFileExtension}")); } // package-info.java await Write(new PackageInfoTemplate { Model = new PackageInfoTemplateModel(cm) - }, _packageInfoFileName); + }, Path.Combine(packagePath, _packageInfoFileName)); await Write(new PackageInfoTemplate { Model = new PackageInfoTemplateModel(cm, "implementation") - }, Path.Combine("implementation", _packageInfoFileName)); + }, Path.Combine(packagePath, "implementation", _packageInfoFileName)); + + if (true == AutoRest.Core.Settings.Instance.Host?.GetValue("regenerate-manager").Result) + { + // Manager + await Write( + new AzureServiceManagerTemplate { Model = codeModel }, + Path.Combine(packagePath, "implementation", codeModel.ServiceName + "Manager" + ImplementationFileExtension)); + + // POM + await Write(new AzurePomTemplate { Model = codeModel }, "pom.xml"); + } } } } diff --git a/src/azurefluent/Model/MethodJvaf.cs b/src/azurefluent/Model/MethodJvaf.cs index db6ea8d569..88da06a653 100644 --- a/src/azurefluent/Model/MethodJvaf.cs +++ b/src/azurefluent/Model/MethodJvaf.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. using System.Collections.Generic; @@ -223,6 +223,21 @@ private enum MethodType Delete } + private static bool HasSequenceType(IModelType mt) + { + if (mt is SequenceType) + { + return true; + } + + if (mt is CompositeType ct) + { + return ct.Properties.Any(p => HasSequenceType(p.ModelType)); + } + + return false; + } + private static MethodType GetMethodType(MethodJvaf method) { Regex leading = new Regex("^/+"); @@ -233,7 +248,7 @@ private static MethodType GetMethodType(MethodJvaf method) var urlSplits = methodUrl.Split('/'); if ((urlSplits.Count() == 5 || urlSplits.Count() == 7) && StringComparer.OrdinalIgnoreCase.Equals(urlSplits[0], "subscriptions") - && method.ReturnType.Body is SequenceType) + && HasSequenceType(method.ReturnType.Body)) { if (urlSplits.Count() == 5) {