using System.Reflection; using Connected.Configuration.Environment; using Connected.Data.Schema; using Connected.Entities; using Connected.ServiceModel; using Connected.ServiceModel.Transactions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace Connected.Instance; internal static class EntitySynchronizer { public static async Task Synchronize(IServiceProvider services, string value) { var logger = services.GetService>(); if (logger is null) throw new NullReferenceException(nameof(ILogger)); logger.LogTrace("Starting entities synchronization."); if (services.GetService() is not IContextProvider provider) throw new NullReferenceException(nameof(IContextProvider)); using var ctx = provider.Create(); if (ctx.GetService() is not IEnvironmentService environmentService) throw new NullReferenceException(nameof(IEnvironmentService)); if (ctx.GetService() is not ISchemaService schemaService) { logger.LogWarning("ISchemaService is not registered. Entity synchronization skipped."); return; } /* * entitySynchronization = rebuild */ if (string.Equals(value, "rebuild", StringComparison.OrdinalIgnoreCase)) { logger.LogTrace("Rebuilding entities."); foreach (var assembly in environmentService.MicroServices) await Synchronize(schemaService, assembly, logger); } else { /* * entitySynchronization = token1, token2,... */ var tokens = value.Split(','); /* * token1: assembly : assemblyName * token2: type : typeName */ foreach (var token in tokens) { var subTokens = token.Split(':'); if (subTokens.Length != 2) throw new ArgumentException("Invalid entitySyncronization token '{token}'. Expected assembly:[assembly] or type:[type].", token); if (string.Equals(subTokens[0], "assembly", StringComparison.OrdinalIgnoreCase)) { logger.LogTrace("Loading assembly '{assembly}'", subTokens[1]); await Synchronize(schemaService, Assembly.Load(AssemblyName.GetAssemblyName(subTokens[1])), logger); } else if (string.Equals(subTokens[1], "type", StringComparison.OrdinalIgnoreCase)) { logger.LogTrace("Loading type '{type}'", subTokens[1]); if (Type.GetType(subTokens[1]) is not Type type) { logger.LogWarning("Entity type '{type}' could not be loaded. Synchronization on the specified type could not be performed.", subTokens[1]); continue; } await Synchronize(schemaService, new List { type }); } } } logger.LogTrace("Commiting snchronization."); if (ctx.GetService() is ITransactionContext transaction) await transaction.Commit(); logger.LogTrace("Snchronization completed."); } private static async Task Synchronize(ISchemaService schemaService, Assembly assembly, ILogger logger) { var entities = new List(); foreach (var type in assembly.GetTypes()) { if (type.IsAbstract || !type.IsAssignableTo(typeof(IEntity))) continue; entities.Add(type); } if (entities.Any()) await Synchronize(schemaService, entities); } private static async Task Synchronize(ISchemaService schemaService, List entities) { await schemaService.Synchronize(entities); } }