/// <summary> /// Sorts messaging objects by their name. /// </summary> /// <param name="x">The first item to be compared.</param> /// <param name="y">The second item to be compared.</param> /// <returns>An integer indicating the comparison between x and y.</returns> public static int SortTargetMessagingObjectByName(MessagingObject x, MessagingObject y) { _ = x ?? throw new ArgumentNullException(nameof(x)); _ = y ?? throw new ArgumentNullException(nameof(y)); return(string.Compare(x.Name, y.Name, true, CultureInfo.CurrentCulture)); }
/// <summary> /// Generates the files associated with a list of resource templates. /// </summary> /// <param name="messagingObject">The messaging object associated with the list of resource templates.</param> /// <param name="templatePaths">The list of source template paths.</param> /// <param name="conversionPathRoot">The root path for all converted files.</param> /// <returns></returns> private async Task<int> GenerateFilesAsync(MessagingObject messagingObject, IEnumerable<DirectoryInfo> templatePaths, DirectoryInfo conversionPathRoot) { var generatedFiles = 0; if (messagingObject.Resources.Any()) { foreach (var resourceTemplate in messagingObject.Resources) { foreach (var templateFile in resourceTemplate.ResourceTemplateFiles) { var foundTemplate = await GenerateFileAsync(messagingObject, resourceTemplate, templatePaths, templateFile, resourceTemplate.OutputPath, conversionPathRoot).ConfigureAwait(false); if (!foundTemplate) { _logger.LogWarning(WarningMessages.TemplateFileNotFound, templateFile); } else { generatedFiles++; } } } } return generatedFiles; }
/// <summary> /// Creates a scenario stage from the messaging object, /// </summary> /// <param name="mo">The messaging object.</param> /// <returns>A new scenario stage.</returns> private static TargetScenarioStage CreateScenarioStage(this MessagingObject mo) { return(new TargetScenarioStage { Name = mo.Name, StageType = mo.GetType().Name, MessagingObject = mo }); }
/// <summary> /// Initializes a scenario from a messaging object. /// </summary> /// <param name="mo">The messaging object.</param> /// <returns>A new scenario.</returns> private static TargetScenario CreateScenario(this MessagingObject mo) { var scenario = new TargetScenario { Name = mo.Properties[ModelConstants.ScenarioName].ToString(), Activator = mo.CreateScenarioStage() }; return(scenario); }
/// <summary> /// Generates a template file by loading, rendering and saving the file to the conversion path /// if it is a .liquid file, otherwise just copy the file. /// </summary> /// <param name="messagingObject">The messaging object associated with the list of resource templates.</param> /// <param name="resourceTemplate">The resource template for this render.</param> /// <param name="templatePaths">The list of source template paths.</param> /// <param name="templateFile">The template file.</param> /// <param name="templateOutputPath">The output path for template files.</param> /// <param name="conversionPathRoot">The root path for all converted files.</param> /// <returns></returns> private async Task<bool> GenerateFileAsync(MessagingObject messagingObject, TargetResourceTemplate resourceTemplate, IEnumerable<DirectoryInfo> templatePaths, string templateFile, string templateOutputPath, DirectoryInfo conversionPathRoot) { var foundTemplate = false; foreach (var templatePath in templatePaths) { var templateFilePath = new FileInfo(Path.Combine(templatePath.FullName, templateFile)); if (_fileRepository.DoesFileExist(templateFilePath.FullName)) { // Check extension if (templateFilePath.Extension.ToUpperInvariant() == ".liquid".ToUpperInvariant()) { _logger.LogTrace(TraceMessages.LoadingTemplate, templateFilePath.FullName); // Load template var templateContent = await _repository.LoadTemplateAsync(templateFilePath.FullName).ConfigureAwait(false); _logger.LogDebug(TraceMessages.RenderingTemplate, templateFilePath.FullName); // Render template var renderedContent = await _renderer.RenderTemplateAsync(templateContent, Model, messagingObject, resourceTemplate).ConfigureAwait(false); // Set output file path var outputFilePath = new FileInfo(Path.Combine(conversionPathRoot.FullName, templateOutputPath, Path.GetFileNameWithoutExtension(templateFilePath.Name))); _logger.LogTrace(TraceMessages.SavingTemplate, outputFilePath.FullName); // Save rendered template await _repository.SaveTemplateAsync(outputFilePath.FullName, renderedContent).ConfigureAwait(false); } else { // Set output file path var outputFilePath = new FileInfo(Path.Combine(conversionPathRoot.FullName, templateOutputPath, templateFilePath.Name)); _logger.LogDebug(TraceMessages.CopyingTemplate, templateFilePath.FullName, outputFilePath.FullName); // Create output path if some directories don't exist if (!_fileRepository.DoesDirectoryExist(outputFilePath.FullName)) { _fileRepository.CreateDirectory(outputFilePath.DirectoryName); } // Just a normal file, copy it to output path _fileRepository.CopyFile(templateFilePath.FullName, outputFilePath.FullName); } foundTemplate = true; } } return foundTemplate; }
/// <summary> /// Renders the properties of the messaging object. /// </summary> /// <param name="containerNode">The HTML container to render into.</param> /// <param name="messagingObject">The messaging object.</param> private static void RenderMessagingObjectProperties(HtmlNode containerNode, MessagingObject messagingObject) { containerNode.AppendChild(CreateNodeWithSnippetContent(string.Format(CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetHeading, HtmlResources.AnalysisHeadingProperties))); if (messagingObject.Properties == null || messagingObject.Properties.Count == 0) { // Add a placeholder if there are no relationships. containerNode.AppendChild( CreateNodeWithSnippetContent( string.Format( CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetInformationMessage, HtmlResources.AnalysisMessageNoProperties))); } else { RenderMessagingObjectPropertyDictionary(containerNode, messagingObject.Properties, string.Empty); } }
/// <summary> /// Writes the messages associated with the item. /// </summary> /// <param name="containerNode">The HTML container to render into.</param> /// <param name="messagingObject">The messaging object.</param> private static void RenderMessagingObjectMessages(HtmlNode containerNode, MessagingObject messagingObject) { containerNode.AppendChild(CreateNodeWithSnippetContent(string.Format(CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetHeading, HtmlResources.AnalysisHeadingMessages))); if (messagingObject.ReportMessages == null || messagingObject.ReportMessages.Count == 0) { // Add a placeholder if there are no report messages. containerNode.AppendChild(CreateNodeWithSnippetContent(string.Format(CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetInformationMessage, HtmlResources.AnalysisMessageNoMessages))); } else { foreach (var item in messagingObject.ReportMessages) { if (item.Severity == MessageSeverity.Error) { containerNode.AppendChild( CreateNodeWithSnippetContent( string.Format( CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetErrorMessage, item.Message))); } else if (item.Severity == MessageSeverity.Warning) { containerNode.AppendChild( CreateNodeWithSnippetContent( string.Format( CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetWarningMessage, item.Message))); } else { containerNode.AppendChild( CreateNodeWithSnippetContent( string.Format( CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetInformationMessage, item.Message))); } } } }
public void SortTargetMessagingObjectByNameXYEqual(MessagingObject x, MessagingObject y, int result) { "Given a resource x" .x(() => x = new DocumentMessage() { Name = "z" }); "And a resource relationship to compare to" .x(() => y = new DocumentMessage() { Name = "z" }); "When comparing x and y" .x(() => result = Comparers.SortTargetMessagingObjectByName(x, y)); "Expect x to be less than y" .x(() => { result.Should().Be(0); }); }
/// <summary> /// Writes the links associated with the item. /// </summary> /// <param name="containerNode">The HTML container to render into.</param> /// <param name="messagingObject">The messaging object.</param> private static void RenderMessagingObjectLinks(HtmlNode containerNode, MessagingObject messagingObject) { containerNode.AppendChild(CreateNodeWithSnippetContent(string.Format(CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetHeading, HtmlResources.AnalysisHeadingLinks))); if (messagingObject.ReportLinks == null || messagingObject.ReportLinks.Count == 0) { // Add a placeholder if there are no relationships. containerNode.AppendChild(CreateNodeWithSnippetContent(string.Format(CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetInformationMessage, HtmlResources.AnalysisMessageNoReferenceLinks))); } else { foreach (var link in messagingObject.ReportLinks) { containerNode.AppendChild( CreateNodeWithSnippetContent( string.Format( CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetTargetReportLink, link, link))); } } }
/// <summary> /// Writes the resources associated with the item. /// </summary> /// <param name="containerNode">The HTML container to render into.</param> /// <param name="messagingObject">The messaging object.</param> private static void RenderMessagingObjectResources(HtmlNode containerNode, MessagingObject messagingObject) { containerNode.AppendChild(CreateNodeWithSnippetContent(string.Format(CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetHeading, HtmlResources.AnalysisHeadingResources))); if (messagingObject.Resources == null || messagingObject.Resources.Count == 0) { // Add a placeholder if there are no relationships. containerNode.AppendChild(CreateNodeWithSnippetContent(string.Format(CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetInformationMessage, HtmlResources.AnalysisMessageNoResources))); } else { foreach (var resource in messagingObject.Resources) { containerNode.AppendChild( CreateNodeWithSnippetContent( string.Format( CultureInfo.CurrentCulture, HtmlResources.AnalysisSnippetTargetResource, ResourceFormatter.GetTargetResourceIconFromType(resource.ResourceType), ResourceFormatter.GetTargetResourceFriendlyName(resource.ResourceType), resource.ResourceName))); } } }
public void RenderTemplateAsyncWithMissingMessagingObjectWithWarning(ITemplateRenderer renderer, AzureIntegrationServicesModel model, MessagingObject messagingObject, string templateContent, string renderedContent, Exception e) { "Given a template renderer" .x(() => renderer = new LiquidTemplateRenderer(_mockLogger.Object)); "And a model" .x(() => model = _model); "And a missing messaging object" .x(() => messagingObject = new TopicChannel("MissingChannel") { Key = "MessageBus:MissingApp:MissingChannel" }); "And a template content" .x(() => templateContent = _templateChannelContent); "When rendering the template" .x(async() => e = await Record.ExceptionAsync(async() => renderedContent = await renderer.RenderTemplateAsync(templateContent, model, messagingObject))); "Then the render should succeed" .x(() => e.Should().BeNull()); "And the rendered content should not have expected values from the model" .x(() => { renderedContent.Should().NotBeNull().And.Be("").And.NotContainAny("{{").And.NotContainAny("}}"); // Verify warning was raised _mockLogger.Verify(l => l.Log( It.Is <LogLevel>(l => l == LogLevel.Warning), It.IsAny <EventId>(), It.Is <It.IsAnyType>((v, t) => v.ToString().Contains("does not appear in the target model", StringComparison.CurrentCultureIgnoreCase)), It.IsAny <Exception>(), It.Is <Func <It.IsAnyType, Exception, string> >((v, t) => true)), Times.Once); }); }
public void RenderTemplateAsyncWithResourceTemplateWithSuccess(ITemplateRenderer renderer, AzureIntegrationServicesModel model, MessagingObject messagingObject, TargetResourceTemplate resourceTemplate, string templateContent, string renderedContent, Exception e) { "Given a template renderer" .x(() => renderer = new LiquidTemplateRenderer(_mockLogger.Object)); "And a model" .x(() => model = _model); "And a messaging object" .x(() => messagingObject = model.FindMessagingObject("ContosoMessageBus:System:FtpReceive").messagingObject); "And a resource template object" .x(() => resourceTemplate = new TargetResourceTemplate() { ResourceName = "endpointFtpReceiveLogicAppConsumption" }); "And a template content" .x(() => templateContent = _templateResourceTemplateContent); "When rendering the template" .x(async() => e = await Record.ExceptionAsync(async() => renderedContent = await renderer.RenderTemplateAsync(templateContent, model, null, resourceTemplate))); "Then the render should succeed" .x(() => e.Should().BeNull()); "And the rendered content should have expected values from the model" .x(() => { renderedContent.Should().NotBeNull().And.ContainAny("endpointFtpReceiveLogicAppConsumption").And.NotContainAny("{{").And.NotContainAny("}}"); }); }
public void RenderTemplateAsyncWithIntermediaryWithSuccess(ITemplateRenderer renderer, AzureIntegrationServicesModel model, MessagingObject messagingObject, string templateContent, string renderedContent, Exception e) { "Given a template renderer" .x(() => renderer = new LiquidTemplateRenderer(_mockLogger.Object)); "And a model" .x(() => model = _model); "And a messaging object" .x(() => messagingObject = model.FindMessagingObject("ContosoMessageBus:System:MessageAgent").messagingObject); "And a template content" .x(() => templateContent = _templateIntermediaryContent); "When rendering the template" .x(async() => e = await Record.ExceptionAsync(async() => renderedContent = await renderer.RenderTemplateAsync(templateContent, model, messagingObject))); "Then the render should succeed" .x(() => e.Should().BeNull()); "And the rendered content should have expected values from the model" .x(() => { renderedContent.Should().NotBeNull().And.ContainAny("MessageAgent").And.NotContainAny("{{").And.NotContainAny("}}"); }); }
/// <summary> /// Populates the target resources from configuration for the specified messaging object. /// </summary> /// <param name="model">The model.</param> /// <param name="config">The YAML configuration set.</param> /// <param name="messagingObject">The messaging object.</param> private void PopulateTargetResources(AzureIntegrationServicesModel model, IEnumerable <YamlStream> config, MessagingObject messagingObject) { if (messagingObject.ResourceMapKey != null) { _logger.LogDebug(TraceMessages.LoadingTargetResources, messagingObject.Key); // Find resource map var resourceKeyList = FindResourcesForMap(config, messagingObject.ResourceMapKey); if (resourceKeyList != null) { foreach (var resourceKeyNode in resourceKeyList) { var resourceKey = (YamlScalarNode)resourceKeyNode; _logger.LogTrace(TraceMessages.LookingForTemplatesForResource, resourceKey.Value); // Find targets for resource var targetsList = FindTargetsForResource(config, resourceKey.Value); if (targetsList != null) { _logger.LogDebug(TraceMessages.FilteringResourcesByTarget, model.MigrationTarget.TargetEnvironment); foreach (var targetNode in targetsList) { var target = (YamlMappingNode)targetNode; // Get target name var targetNameNode = (YamlSequenceNode)target.Children["target"]; var targetNames = targetNameNode.Select(t => ((YamlScalarNode)t).Value.ToUpperInvariant()); if (targetNames.Contains(model.MigrationTarget.TargetEnvironment.ToString("G").ToUpperInvariant())) { if (target.Children.ContainsKey("templates")) { _logger.LogTrace(TraceMessages.FoundTemplatesForTarget, model.MigrationTarget.TargetEnvironment, resourceKey.Value); // Get templates var templateKeyList = target.Children["templates"] as YamlSequenceNode; // Check if we have any templates if (templateKeyList != null) { foreach (var templateKeyNode in templateKeyList) { var templateKey = (YamlScalarNode)templateKeyNode; var templateNode = FindTemplate(config, templateKey.Value); if (templateNode != null) { // Create target resource var targetResourceTemplate = CreateTargetResourceTemplate(model, templateKey, templateNode); messagingObject.Resources.Add(targetResourceTemplate); } } } } else { _logger.LogTrace(TraceMessages.NoTemplatesForTarget, model.MigrationTarget.TargetEnvironment, resourceKey.Value); } if (target.Children.ContainsKey("snippets")) { _logger.LogTrace(TraceMessages.FoundSnippetsForTarget, model.MigrationTarget.TargetEnvironment, resourceKey.Value); // Get snippets var snippetKeyList = (YamlSequenceNode)target.Children["snippets"]; foreach (var snippetKeyNode in snippetKeyList) { var snippetKey = (YamlScalarNode)snippetKeyNode; var snippetNode = FindSnippet(config, snippetKey.Value); if (snippetNode != null) { // Create target resource var targetResourceSnippet = CreateTargetResourceSnippet(model, snippetKey, snippetNode); messagingObject.Snippets.Add(targetResourceSnippet); } } } else { _logger.LogTrace(TraceMessages.NoSnippetsForTarget, model.MigrationTarget.TargetEnvironment, resourceKey.Value); } } } } } } else { _logger.LogWarning(WarningMessages.ResourceMapMissingInConfiguration, messagingObject.ResourceMapKey, messagingObject.Name); } } else { _logger.LogDebug(TraceMessages.ResourceMapKeyNotSpecified, messagingObject.Name, messagingObject.Type); } }
/// <summary> /// Renders a template using a Liquid template engine. /// </summary> /// <param name="templateContent">The template content to render.</param> /// <param name="model">The model used to provide properties to Liquid templates.</param> /// <param name="messagingObject">An optional messaging object to add to the variable context, accessible to templates.</param> /// <param name="resourceTemplate">An optional resource template object to add to the variable context, accessible to templates.</param> /// <returns>The rendered template content.</returns> public async Task <string> RenderTemplateAsync(string templateContent, AzureIntegrationServicesModel model, MessagingObject messagingObject = null, TargetResourceTemplate resourceTemplate = null) { _ = model ?? throw new ArgumentNullException(nameof(model)); _ = templateContent ?? throw new ArgumentNullException(nameof(templateContent)); // Create variables on script object, to be accessible to Liquid templates var scriptObject = new ScriptObject { ["model"] = model }; // Is there a messaging object? if (messagingObject != null) { var messagingObjects = model.FindMessagingObject(messagingObject.Key); if (messagingObjects.messageBus != null) { scriptObject["message_bus"] = messagingObjects.messageBus; if (messagingObjects.application != null) { scriptObject["application"] = messagingObjects.application; } if (messagingObjects.messagingObject != null) { scriptObject["messaging_object"] = messagingObjects.messagingObject; switch (messagingObjects.messagingObject.Type) { case MessagingObjectType.Message: scriptObject["message"] = (Message)messagingObjects.messagingObject; break; case MessagingObjectType.Channel: scriptObject["channel"] = (Channel)messagingObjects.messagingObject; break; case MessagingObjectType.Intermediary: scriptObject["intermediary"] = (Intermediary)messagingObjects.messagingObject; break; case MessagingObjectType.Endpoint: scriptObject["endpoint"] = (Endpoint)messagingObjects.messagingObject; break; } } } else { // Should never happen, unless the messaging object is not attached to the target model _logger.LogWarning(WarningMessages.MessagingObjectMissingInModel, messagingObject.Key); } } // Is there a resource template? if (resourceTemplate != null) { scriptObject["resource_template"] = resourceTemplate; } // Push variables onto the context _context.PushGlobal(scriptObject); try { // Render template var template = Template.ParseLiquid(templateContent); var renderedContent = await template.RenderAsync(_context).ConfigureAwait(false); return(renderedContent); } finally { // Pop model from context stack _context.PopGlobal(); } }
/// <summary> /// Analyzes the response path of a two way send port to build the route back to the topic channel. /// </summary> /// <param name="intermediaryKeyPrefix">The prefix for the intermediary key.</param> /// <param name="sourceApplication">The application object in the source model.</param> /// <param name="targetApplication">The application object in the target model.</param> /// <param name="sendPortSource">The send port source.</param> /// <param name="sendPort">The send port resource item.</param> /// <param name="endpointAdapter">The endpoint adapter which triggers the response.</param> private void AnalyzeSendPortResponse(string intermediaryKeyPrefix, ResourceItem sourceApplication, Application targetApplication, SendPort sendPortSource, ResourceItem sendPort, MessagingObject endpointAdapter) { _logger.LogDebug(TraceMessages.SendPortIsTwoWay, RuleName, sendPort.Name); // Format the keys. var applicationName = targetApplication.Name.FormatKey(); var sendPortName = sendPort.Name.FormatKey(); // Set the scenario name on the endpoint adapter. endpointAdapter.Properties.Add(ModelConstants.ScenarioName, $"{applicationName}.{sendPortName}.Response"); var route = new List <MessagingObject> { endpointAdapter }; // Create the intermediaries for the pipeline route.AddRange(CreateReceivePipelineIntermediaries(intermediaryKeyPrefix, sourceApplication, sendPortSource.ReceivePipeline, sendPortSource.ReceivePipelineCustomConfiguration)); // If there is a map, create the intermediary if (sendPortSource.InboundTransforms != null && sendPortSource.InboundTransforms.Any()) { // Find map resource items var transforms = sendPort.FindRelatedResourcesByType(Model, ResourceRelationshipType.ReferencesTo, ModelConstants.ResourceMap); // Add to route var intermediary = CreateMapIntermediary(intermediaryKeyPrefix, targetApplication, transforms); if (intermediary != null) { route.Add(intermediary); } } else { _logger.LogTrace(TraceMessages.NoReceiveMapSpecifiedOnSendPort, RuleName, sendPortSource.Name); } // Create the message agent intermediaries route.AddRange(CreateMessageAgentIntermediaries(intermediaryKeyPrefix, _messageBoxChannelKey, false, null)); // Binds the route by adding routing slip router intermediaries between the intermediaries in the response from the send port var boundRoute = BindResponseRoute(intermediaryKeyPrefix, targetApplication, sendPortSource, route); // Binds the channels between the endpoint and intermediaries up to the message box (topic channel) BindResponseChannels(intermediaryKeyPrefix, targetApplication, sendPortSource, boundRoute); }