|
|
|
|
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<ILogger<ServerStartup>>();
|
|
|
|
|
|
|
|
|
|
if (logger is null)
|
|
|
|
|
throw new NullReferenceException(nameof(ILogger<ServerStartup>));
|
|
|
|
|
|
|
|
|
|
logger.LogTrace("Starting entities synchronization.");
|
|
|
|
|
|
|
|
|
|
if (services.GetService<IContextProvider>() is not IContextProvider provider)
|
|
|
|
|
throw new NullReferenceException(nameof(IContextProvider));
|
|
|
|
|
|
|
|
|
|
using var ctx = provider.Create();
|
|
|
|
|
|
|
|
|
|
if (ctx.GetService<IEnvironmentService>() is not IEnvironmentService environmentService)
|
|
|
|
|
throw new NullReferenceException(nameof(IEnvironmentService));
|
|
|
|
|
|
|
|
|
|
if (ctx.GetService<ISchemaService>() 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[0], "type", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
var typeTokens = subTokens[1].Split("/");
|
|
|
|
|
|
|
|
|
|
if (typeTokens.Length != 2)
|
|
|
|
|
throw new ArgumentException("Invalid entitySyncronization token '{token}'. Expected type:[assembly]/[type].", subTokens[1]);
|
|
|
|
|
|
|
|
|
|
var qualifier = $"{typeTokens[1]}, {typeTokens[0]}";
|
|
|
|
|
|
|
|
|
|
logger.LogTrace("Loading type '{type}'", qualifier);
|
|
|
|
|
|
|
|
|
|
if (Type.GetType(qualifier) is not Type type)
|
|
|
|
|
{
|
|
|
|
|
logger.LogWarning("Entity type '{type}' could not be loaded. Synchronization on the specified type could not be performed.", qualifier);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await Synchronize(schemaService, new List<Type> { type });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.LogTrace("Commiting snchronization.");
|
|
|
|
|
|
|
|
|
|
if (ctx.GetService<ITransactionContext>() is ITransactionContext transaction)
|
|
|
|
|
await transaction.Commit();
|
|
|
|
|
|
|
|
|
|
logger.LogTrace("Snchronization completed.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static async Task Synchronize(ISchemaService schemaService, Assembly assembly, ILogger<ServerStartup> logger)
|
|
|
|
|
{
|
|
|
|
|
var entities = new List<Type>();
|
|
|
|
|
|
|
|
|
|
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<Type> entities)
|
|
|
|
|
{
|
|
|
|
|
await schemaService.Synchronize(entities);
|
|
|
|
|
}
|
|
|
|
|
}
|