/// <summary> /// Checks whether the return type of a given method can be wrapped in a Java interface impl and wrapper /// can expose it through HasInner interface. /// </summary> /// <param name="method">the method to check its return type eligibility to be wrappable</param> /// <returns></returns> public static bool HasWrappableReturnType(this Azure.Fluent.Model.MethodJvaf method) { if (method.ReturnTypeJva != null) { CompositeTypeJvaf returnModelType = null; IModelType mtype = method.ReturnTypeJva.BodyClientType; if (mtype is CompositeTypeJvaf) { returnModelType = (CompositeTypeJvaf)mtype; } else if (mtype is SequenceTypeJva) { mtype = ((SequenceTypeJva)mtype).ElementType; if (mtype is CompositeTypeJvaf) { returnModelType = (CompositeTypeJvaf)mtype; } } // if (returnModelType != null) { string returnModelTypeName = returnModelType.Name.Value; return(returnModelTypeName.EndsWith("Inner", StringComparison.OrdinalIgnoreCase)); } else { return(false); } } else { return(false); } }
/// <summary> /// Derive and return optional definition stages from the create member variables. /// </summary> protected List <FluentDefinitionOrUpdateStage> OptionalDefinitionStages(List <FluentDefinitionOrUpdateStage> initialStages) { if (this.optDefStages != null) { return(this.optDefStages); } this.optDefStages = new List <FluentDefinitionOrUpdateStage>(); if (!this.SupportsCreating) { return(this.optDefStages); } var dmvs = this.disambiguatedMemberVariables ?? throw new ArgumentNullException("dMemberVariables"); var payloadInnerModelVariable = this.CompositePayloadVariable; // Stages for setting optional properties of "create body payload" // if (payloadInnerModelVariable != null) { string payloadInnerModelVariableName = payloadInnerModelVariable.VariableName; CompositeTypeJvaf payloadType = (CompositeTypeJvaf)payloadInnerModelVariable.FromParameter.ClientType; var payloadOptinalProperties = payloadType .ComposedProperties .Where(p => !p.IsReadOnly && !p.IsRequired) .Where(p => !propertiesOfPayloadToSkip.Contains(p.Name.ToString(), StringComparer.OrdinalIgnoreCase)) .OrderBy(p => p.Name.ToLowerInvariant()); FluentDefinitionOrUpdateStage creatableStage = new FluentDefinitionOrUpdateStage(this.resourceName, "WithCreate"); foreach (Property pro in payloadOptinalProperties) { string methodName = $"with{pro.Name.ToPascalCase()}"; string parameterName = pro.Name; string methodParameterDecl = $"{pro.ModelTypeName} {parameterName}"; FluentDefinitionOrUpdateStageMethod method = new FluentDefinitionOrUpdateStageMethod(methodName, methodParameterDecl, pro.ModelType as IModelTypeJv) { CommentFor = new Dictionary <string, string> { { parameterName, pro.Documentation } }, Body = $"{(dmvs.MemeberVariablesForCreate[payloadInnerModelVariableName]).VariableAccessor}.{methodName}({parameterName});" }; string interfaceName = $"With{pro.Name.ToPascalCase()}"; FluentDefinitionOrUpdateStage stage = new FluentDefinitionOrUpdateStage(this.resourceName, interfaceName); this.optDefStages.Add(stage); stage.Methods.Add(method); stage.Methods.ForEach(m => { m.NextStage = creatableStage; }); } } return(this.optDefStages); }
public NonWrappableModel(CompositeTypeJvaf rawModel) { var innerModelName = rawModel.Name.Value; if (innerModelName.EndsWith("Inner", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException($"NonWrappableModel requires an inner model without 'Inner' suffix but received inner model '{innerModelName}'."); } this.RawModel = rawModel; }
/// <summary> /// Creates WrappableFluentModel describing a Fluent Model that wraps the given Inner Model. /// </summary> /// <param name="innerModel">the inner model [that has 'Inner' suffix in it's name]</param> public WrappableFluentModel(CompositeTypeJvaf innerModel) { var innerModelName = innerModel.Name.Value; if (!innerModelName.EndsWith("Inner", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException($"WrappableFluentModel requires 'Inner' suffix for the inner model it wraps but received inner model '{innerModelName}' without suffix."); } this.JavaInterfaceName = Utils.TrimInnerSuffix(innerModelName); this.RawModel = innerModel; }
public FluentModel(CompositeTypeJvaf innerModel) { var n = innerModel.Name.Value; if (!n.EndsWith("Inner", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException($"Fluent inner model should have inner suffix {n}"); } this.javaInterfaceName = n.Substring(0, n.Length - "Inner".Length); this.InnerModel = innerModel; }
private CompositeTypeJvaf standardInnerModel; // The derived standard inner model. /// <summary> /// The "Segment Fluent Method Group" composes a bunch of methods, now given all these methods identify /// the "Standard Inner Model" from the standard methods. /// </summary> public void DeriveStandardInnerModelForMethodGroup() { if (this.derivedStandardInnerModel) { return; } this.derivedStandardInnerModel = true; // Find "ONE" fluent model that can be used across "Standard methods" // 1. (GetByResourceGroup | ListByResourceGroup | ListBySubscription | Create in RG) // 2. (GetByImmediateParent | ListByImmediateParent | Create in Parent) // // Derive an "inner model then a fluent model" that represents the return type of standard methods // in this fluent model. We want all thoses standard methods to return same fluent type though the // inner methods can return different inner model types. // if (ResourceGetDescription.SupportsGetByResourceGroup) { this.standardInnerModel = ResourceGetDescription.GetByResourceGroupMethod.InnerReturnType; } else if (ResourceCreateDescription.SupportsCreating) { this.standardInnerModel = ResourceCreateDescription.CreateMethod.InnerReturnType; } else if (ResourceListingDescription.SupportsListByResourceGroup) { this.standardInnerModel = ResourceListingDescription.ListByResourceGroupMethod.InnerReturnType; } else if (ResourceListingDescription.SupportsListBySubscription) { this.standardInnerModel = ResourceListingDescription.ListBySubscriptionMethod.InnerReturnType; } // else if (ResourceGetDescription.SupportsGetByImmediateParent) { this.standardInnerModel = ResourceGetDescription.GetByImmediateParentMethod.InnerReturnType; } else if (ResourceListingDescription.SupportsListByImmediateParent) { this.standardInnerModel = ResourceListingDescription.ListByImmediateParentMethod.InnerReturnType; } else if (ResourceUpdateDescription.SupportsUpdating) { this.standardInnerModel = ResourceUpdateDescription.UpdateMethod.InnerReturnType; } }
public static bool IsTrackedResource(CompositeTypeJvaf model) { if (model == null) { return(false); } else { // bool hasId = model.ComposedProperties.Any(p => p.Name.ToLowerInvariant().Equals("id") /*&& p.IsReadOnly*/); bool hasName = model.ComposedProperties.Any(p => p.Name.ToLowerInvariant().Equals("name") /*&& p.IsReadOnly*/); bool hasType = model.ComposedProperties.Any(p => p.Name.ToLowerInvariant().Equals("type") /*&& p.IsReadOnly*/); bool hasLocation = model.ComposedProperties.Any(p => p.Name.ToLowerInvariant().Equals("location")); bool hasTags = model.ComposedProperties.Any(p => p.Name.ToLowerInvariant().Equals("tags")); // return(hasId && hasName && hasType && hasLocation && hasTags); } }
public StandardModel(FluentMethodGroup group, CompositeTypeJvaf standardInnerModel) : base(standardInnerModel) { switch (group.Type) { case MethodGroupType.GroupableTopLevel: this.Type = StanardModelType.GroupableTopLevel; break; case MethodGroupType.NonGroupableTopLevel: this.Type = StanardModelType.NonGroupableTopLevel; break; case MethodGroupType.Nested: this.Type = StanardModelType.Nested; break; default: throw new ArgumentException($"group with type '{group.Type}' is not eligible to have a standard model."); } this.FluentMethodGroup = group; }
/// <summary> /// Derive and return required definition stages from the create member variables. /// </summary> protected List <FluentDefinitionOrUpdateStage> RequiredDefinitionStages(List <FluentDefinitionOrUpdateStage> initialStages) { if (this.reqDefStages != null) { return(this.reqDefStages); } this.reqDefStages = new List <FluentDefinitionOrUpdateStage>(); if (!this.SupportsCreating) { return(this.reqDefStages); } var dmvs = this.disambiguatedMemberVariables ?? throw new ArgumentNullException("dMemberVariables"); FluentDefinitionOrUpdateStage currentStage = null; if (initialStages != null) { this.reqDefStages.AddRange(initialStages); currentStage = this.reqDefStages.LastOrDefault(); } // 1. stages for setting create arguments except "create body payload" // foreach (var memberVariable in this.NotParentRefNotCompositePayloadButPositionalAndOtherMemberVariables) { string methodName = $"with{memberVariable.FromParameter.Name.ToPascalCase()}"; string parameterName = memberVariable.VariableName; string methodParameterDecl = $"{memberVariable.VariableTypeName} {parameterName}"; FluentDefinitionOrUpdateStageMethod method = new FluentDefinitionOrUpdateStageMethod(methodName, methodParameterDecl, memberVariable.VariableType) { CommentFor = new Dictionary <string, string> { { parameterName, memberVariable.FromParameter.Documentation } }, Body = $"{(dmvs.MemeberVariablesForCreate[memberVariable.VariableName]).VariableAccessor} = {parameterName};" }; string interfaceName = $"With{memberVariable.FromParameter.Name.ToPascalCase()}"; FluentDefinitionOrUpdateStage nextStage = new FluentDefinitionOrUpdateStage(this.resourceName, interfaceName); this.reqDefStages.Add(nextStage); nextStage.Methods.Add(method); // if (currentStage != null) { currentStage.Methods.ForEach(m => { m.NextStage = nextStage; }); } currentStage = nextStage; } // 2. stages for setting required properties of "create body composite payload" // var compositePayloadVariable = this.CompositePayloadVariable; if (compositePayloadVariable != null) { string payloadInnerModelVariableName = compositePayloadVariable.VariableName; CompositeTypeJvaf payloadType = (CompositeTypeJvaf)compositePayloadVariable.FromParameter.ClientType; var payloadRequiredProperties = payloadType.ComposedProperties .Where(p => !p.IsReadOnly && p.IsRequired) .Where(p => !propertiesOfPayloadToSkip.Contains(p.Name.ToString(), StringComparer.OrdinalIgnoreCase)) .OrderBy(p => p.Name.ToLowerInvariant()); foreach (Property pro in payloadRequiredProperties) { string methodName = $"with{pro.Name.ToPascalCase()}"; string parameterName = pro.Name; string methodParameterDecl = $"{pro.ModelTypeName} {parameterName}"; FluentDefinitionOrUpdateStageMethod method = new FluentDefinitionOrUpdateStageMethod(methodName, methodParameterDecl, pro.ModelType as IModelTypeJv) { CommentFor = new Dictionary <string, string> { { parameterName, pro.Documentation } }, Body = $"{(dmvs.MemeberVariablesForCreate[payloadInnerModelVariableName]).VariableAccessor}.{methodName}({parameterName});" }; string interfaceName = $"With{pro.Name.ToPascalCase()}"; FluentDefinitionOrUpdateStage nextStage = new FluentDefinitionOrUpdateStage(this.resourceName, interfaceName); this.reqDefStages.Add(nextStage); nextStage.Methods.Add(method); if (currentStage != null) { currentStage.Methods.ForEach(m => { m.NextStage = nextStage; }); } currentStage = nextStage; } } FluentDefinitionOrUpdateStage creatableStage = new FluentDefinitionOrUpdateStage(this.resourceName, "WithCreate"); if (currentStage != null) { currentStage.Methods.ForEach(m => { m.NextStage = creatableStage; }); } return(this.reqDefStages); }
/// <summary> /// Create and return "Update Stages" from the member variables. /// </summary> public virtual List <FluentDefinitionOrUpdateStage> UpdateStages() { if (this.updateStages != null) { return(this.updateStages); } this.updateStages = new List <FluentDefinitionOrUpdateStage>(); if (!this.SupportsUpdating) { return(this.updateStages); } var dmvs = this.disambiguatedMemberVariables ?? throw new ArgumentNullException("dMemberVariables"); FluentDefinitionOrUpdateStage updateGrouping = new FluentDefinitionOrUpdateStage(this.resourceName, "Update"); // During resource update changing parent ref properties and other path properties are not allowed // IEnumerable <FluentModelMemberVariable> nonExpandableUpdatableMemberVariables = this.NotParentRefNotPositionalPathAndNotCompositePayloadMemberVariables; foreach (var memberVariable in nonExpandableUpdatableMemberVariables) { string methodName = $"with{memberVariable.FromParameter.Name.ToPascalCase()}"; string parameterName = memberVariable.VariableName; string methodParameterDecl = $"{memberVariable.VariableTypeName} {parameterName}"; FluentDefinitionOrUpdateStageMethod method = new FluentDefinitionOrUpdateStageMethod(methodName, methodParameterDecl, memberVariable.VariableType) { CommentFor = new Dictionary <string, string> { { parameterName, memberVariable.FromParameter.Documentation } }, Body = $"{(dmvs.MemeberVariablesForUpdate[memberVariable.VariableName]).VariableAccessor} = {parameterName};" }; string interfaceName = $"With{memberVariable.FromParameter.Name.ToPascalCase()}"; FluentDefinitionOrUpdateStage stage = new FluentDefinitionOrUpdateStage(this.resourceName, interfaceName); this.updateStages.Add(stage); stage.Methods.Add(method); stage.Methods.ForEach(m => { m.NextStage = updateGrouping; }); } var payloadInnerModelVariable = this.CompositePayloadVariable; if (payloadInnerModelVariable != null) { string payloadInnerModelVariableName = payloadInnerModelVariable.VariableName; CompositeTypeJvaf payloadType = (CompositeTypeJvaf)payloadInnerModelVariable.FromParameter.ClientType; var payloadOptionalProperties = payloadType .ComposedProperties .Where(p => !p.IsReadOnly && !p.IsRequired) .Where(p => !propertiesOfPayloadToSkip.Contains(p.Name.ToString(), StringComparer.OrdinalIgnoreCase)) .OrderBy(p => p.Name.ToLowerInvariant()); foreach (Property pro in payloadOptionalProperties) { string methodName = $"with{pro.Name.ToPascalCase()}"; string parameterName = pro.Name; string methodParameterDecl = $"{pro.ModelTypeName} {parameterName}"; FluentDefinitionOrUpdateStageMethod method = new FluentDefinitionOrUpdateStageMethod(methodName, methodParameterDecl, pro.ModelType as IModelTypeJv) { CommentFor = new Dictionary <string, string> { { parameterName, pro.Documentation } }, Body = $"{(dmvs.MemeberVariablesForUpdate[payloadInnerModelVariableName]).VariableAccessor}.{methodName}({parameterName});" }; string interfaceName = $"With{pro.Name.ToPascalCase()}"; FluentDefinitionOrUpdateStage stage = new FluentDefinitionOrUpdateStage(this.resourceName, interfaceName); this.updateStages.Add(stage); stage.Methods.Add(method); stage.Methods.ForEach(m => { m.NextStage = updateGrouping; }); } } return(this.updateStages); }
internal void DeriveStandrdFluentModelForMethodGroup() { if (this.derivedFluentModels) { return; } this.derivedFluentModels = true; // Find "ONE" fluent model that can be used across "Standard methods" (GetByResourceGroup | // ListByResourceGroup | ListBySubscription | GetByImmediateParent | ListByImmediateParent | // Create in RG, Update) // // Derive an "inner model then a fluent model" that represents the return type of standard methods // in this fluent model. We want all thoses standard methods to return same fluent type though the // inner methods can return different inner model types. // CompositeTypeJvaf standardModelInner = null; this.innersRequireWrapping = new Dictionary <string, CompositeTypeJvaf>(); if (ResourceGetDescription.SupportsGetByResourceGroup) { standardModelInner = ResourceGetDescription.GetByResourceGroupMethod.InnerReturnType; } else if (ResourceCreateDescription.SupportsCreating) { standardModelInner = ResourceCreateDescription.CreateMethod.InnerReturnType; } else if (ResourceListingDescription.SupportsListByResourceGroup) { standardModelInner = ResourceListingDescription.ListByResourceGroupMethod.InnerReturnType; } else if (ResourceListingDescription.SupportsListBySubscription) { standardModelInner = ResourceListingDescription.ListBySubscriptionMethod.InnerReturnType; } else if (ResourceGetDescription.SupportsGetByImmediateParent) { standardModelInner = ResourceGetDescription.GetByImmediateParentMethod.InnerReturnType; } else if (ResourceListingDescription.SupportsListByImmediateParent) { standardModelInner = ResourceListingDescription.ListByImmediateParentMethod.InnerReturnType; } else if (ResourceUpdateDescription.SupportsUpdating) { standardModelInner = ResourceUpdateDescription.UpdateMethod.InnerReturnType; } // For the "standard model" (FModel) in a FluentMethodGroup we need to gen "FModel wrapModel(ModelInner)" // but if there are different ModelInner types mapping that needs to be mapped to the same FModel // we will be generating one over load per inner -> FModel mapping // if (standardModelInner != null) { this.standardFluentModel = new FluentModel(standardModelInner); if (ResourceGetDescription.SupportsGetByResourceGroup) { var im = ResourceGetDescription.GetByResourceGroupMethod.InnerReturnType; this.innersRequireWrapping.AddIfNotExists(im.ClassName, im); } if (ResourceCreateDescription.SupportsCreating) { var im = ResourceCreateDescription.CreateMethod.InnerReturnType; this.innersRequireWrapping.AddIfNotExists(im.ClassName, im); } if (ResourceListingDescription.SupportsListByResourceGroup) { var im = ResourceListingDescription.ListByResourceGroupMethod.InnerReturnType; this.innersRequireWrapping.AddIfNotExists(im.ClassName, im); } if (ResourceListingDescription.SupportsListBySubscription) { var im = ResourceListingDescription.ListBySubscriptionMethod.InnerReturnType; this.innersRequireWrapping.AddIfNotExists(im.ClassName, im); } if (ResourceGetDescription.SupportsGetByImmediateParent) { var im = ResourceGetDescription.GetByImmediateParentMethod.InnerReturnType; this.innersRequireWrapping.AddIfNotExists(im.ClassName, im); } if (ResourceListingDescription.SupportsListByImmediateParent) { var im = ResourceListingDescription.ListByImmediateParentMethod.InnerReturnType; this.innersRequireWrapping.AddIfNotExists(im.ClassName, im); } if (ResourceUpdateDescription.SupportsUpdating) { var im = ResourceUpdateDescription.UpdateMethod.InnerReturnType; this.innersRequireWrapping.AddIfNotExists(im.ClassName, im); } // Remove wrapping for standard model as each fluent method group takes care of it locally // this.innersRequireWrapping.Remove(this.standardFluentModel.InnerModel.ClassName); } }