using Edge.Core.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Edge.Core.Processor.Dispatcher { public class LegacySettingsXmlFileLoader : IProcessorLoader { protected IServiceProvider services; protected static ILogger mainLogger = NullLogger.Instance; public LegacySettingsXmlFileLoader(IServiceProvider services) { this.services = services; var loggerFactory = services.GetRequiredService(); mainLogger = loggerFactory.CreateLogger("Main"); } public IEnumerable CreateAll() { mainLogger.LogInformation("Use LegacySettingsXmlFileLoader for Processor Meta Config."); Console.WriteLine("Use LegacySettingsXmlFileLoader for Processor Meta Config."); var configurator = this.services.GetRequiredService(); var processorConfigs = configurator.DeviceProcessorConfiguration.Processor.OrderBy(pc => pc.Name).ToList(); mainLogger.LogInformation("==============Instantiate Processors (total: " + processorConfigs.Count() + ")=============="); Console.WriteLine(); Console.WriteLine("==============Instantiate Processors (total: " + processorConfigs.Count() + ")=============="); //List processorInstances = new List(); var createResults = new List(); for (int i = 0; i < processorConfigs.Count; i++) { var pc = processorConfigs[i]; try { mainLogger.LogInformation("[" + i + "]: " + pc.Name + ", " + pc.DeviceProcessorType); Console.WriteLine("[" + i + "]: " + pc.Name + ", " + pc.DeviceProcessorType); var parameters = pc.Parameter;//.Cast(); foreach (var para in parameters) { mainLogger.LogInformation(" " + para.Name + " : " + para.Value); //Console.WriteLine(" " + para.Name + " : " + para.Value); } var processorInstance = ConstructComplexType_Xml_String(pc.DeviceProcessorType, pc.ConstructorArg, parameters, services) as IProcessor; processorInstance.MetaConfigName = pc.Name; createResults.Add(new ProcessorInstanceOperatingResult() { MetaConfig = new ProcessorMetaConfig() { Name = pc.Name, Activated = true, SourceEndpointFullTypeStr = pc.DeviceProcessorType, Type = processorInstance is IAppProcessor ? ProcessorTypeEnum.AppProcessor : ProcessorTypeEnum.DeviceProcessor, Description = "Current using Legacy Settings XmlFile mode, so this is a fake ProcessorMetaConfig" }, //Description = "Legacy Settings XmlFile mode for instantiate a processor, and succeed", Succeed = true, ProcessorInstance = processorInstance, //MetaConfig = mc, }); } catch (Exception eee) { createResults.Add(new ProcessorInstanceOperatingResult() { MetaConfig = new ProcessorMetaConfig() { Name = pc.Name, Activated = true, SourceEndpointFullTypeStr = pc.DeviceProcessorType, Description = "Current using Legacy Settings XmlFile mode, so this is a fake ProcessorMetaConfig" }, //Description = "Legacy Settings XmlFile mode for instantiate a processor, but failed", Succeed = false, //MetaConfig = mc, FailedReason = eee.ToString() }); mainLogger.LogError(" - Failed for instantiate: " + pc.Name + Environment.NewLine + " " + eee.ToString()); Console.BackgroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Black; Console.WriteLine(" - Failed for instantiate: " + pc.Name + Environment.NewLine + " " + eee.ToString().Substring(0, 90) + "..."); Console.ResetColor(); } } mainLogger.LogInformation("==============Instantiate Processors End=============="); Console.WriteLine("==============Instantiate Processors End=============="); return createResults; } public IProcessor Create(string configName) { if (string.IsNullOrEmpty(configName)) throw new ArgumentException(nameof(configName)); var configurator = this.services.GetRequiredService(); var processorConfig = configurator.DeviceProcessorConfiguration.Processor.First(settingsXmlConfig => settingsXmlConfig.Name == configName); var p = ConstructComplexType_Xml_String( processorConfig.DeviceProcessorType, processorConfig.ConstructorArg, processorConfig.Parameter, services) as IProcessor; p.MetaConfigName = processorConfig.Name; return p; } /// /// /// /// nameSpace.ClassA, AssemblyFileName /// /// /// /// protected virtual dynamic ConstructComplexType_Xml_String(string typeFullyQualifiedNameString, string constrStrFromConfig, IEnumerable parameters, IServiceProvider services) { Type processorType = Type.GetType(typeFullyQualifiedNameString); if (processorType == null) { var fallbackToVersion2NameString = Fallback_Version2_ResolveType_Compatbility(typeFullyQualifiedNameString); processorType = Type.GetType(fallbackToVersion2NameString); if (processorType == null) throw new ArgumentException("Could not resolve type: " + typeFullyQualifiedNameString); else typeFullyQualifiedNameString = fallbackToVersion2NameString; } if (string.IsNullOrEmpty(constrStrFromConfig)) { try { //now only support injecting one parameter. var injectingCtor = processorType.GetConstructors().FirstOrDefault(c => c.GetParameters().Length == 1); if (injectingCtor != null && injectingCtor.GetParameters().First().ParameterType == typeof(IServiceProvider)) { mainLogger.LogTrace("Constructing instance(with 1 param ctor and empty param from config) with type: " + processorType.Name); mainLogger.LogTrace(" - ctor parameter with name: " + injectingCtor.GetParameters().First().Name + " is type IServiceProvider, will injecting"); var injectedInstance = Activator.CreateInstance(processorType, new object[] { services }); mainLogger.LogTrace(" Done constructing instance(with 1 param ctor and empty param from config) with type: " + processorType.Name); return injectedInstance; } mainLogger.LogTrace("Constructing instance(with empty param ctor and empty param from config) with type: " + processorType.Name); var parameterlessInstance = Activator.CreateInstance(processorType); mainLogger.LogTrace(" Done constructing instance(with empty param ctor and empty param from config) with type: " + processorType.Name); return parameterlessInstance; } catch (Exception exxx) { //mainLogger.LogError(); throw new InvalidOperationException("CreateInstance(with empty ctor) for: " + typeFullyQualifiedNameString + " failed, " + Environment.NewLine + " exception detail: " + exxx); } } else { List cArgsFromConfig = new List(); var constructorArgStrings = constrStrFromConfig.Replace("\r", "").Replace("\n", "").Split(',').Select(s => s.Trim()).ToArray(); for (int i = 0; i < constructorArgStrings.Length; i++) { var argStr = constructorArgStrings[i]; try { if (!argStr.StartsWith("ref:")) { cArgsFromConfig.Add(readPrimitiveParameterValue(argStr)); } else if (argStr.StartsWith("ref:")) { var refTo = argStr.Substring(4); // quick ref if (refTo.Contains(':')) { var quickRefValuePart = refTo.Split(':').Last(); cArgsFromConfig.Add(readPrimitiveParameterValue(quickRefValuePart)); } else { var refParameter = parameters.First(p => p.Name == refTo); if (!refParameter.Complex) { cArgsFromConfig.Add(readPrimitiveParameterValue(refParameter.Value)); } else { var complexArg = ConstructComplexType_Xml_String(refParameter.Value, refParameter.ConstructorArg, parameters, services); cArgsFromConfig.Add(complexArg); } } } } catch (Exception exxx) { throw new InvalidOperationException("failed for parse constructor arg[" + i + "]: " + argStr + " " + Environment.NewLine + " for type: " + processorType.Name + " " + Environment.NewLine + " detail: " + exxx); } //else if (argStr.StartsWith("refIdArray(")) //{ // var idsString = argStr.Skip("refIdArray(".Length).TakeWhile(p => p != ')') // .Select(c => c.ToString()).Aggregate((acc, n) => acc + n); // var output = processors.Where(p => idsString.Trim().Split('|').ToList().Contains(p.Id.ToString())); // cArgs.Add(output); //} } //var cc = deviceProcessorType.GetConstructors(); try { mainLogger.LogTrace("Constructing instance(with multiple param ctor and " + cArgsFromConfig.Count + " param from config) with type: " + processorType.Name); //now only support injecting one parameter. var injectingCtor = processorType.GetConstructors().FirstOrDefault(c => c.GetParameters().Length == cArgsFromConfig.Count + 1); //for(int c=0;c c.ToString()).Aggregate((acc, n) => acc + ", " + n) + ") for: " + processorType.Name + " failed, \r\n exception detail: " + exxx); } } } protected virtual object readPrimitiveParameterValue(string valueStr) { if (valueStr.StartsWith("ref:")) throw new ArgumentException("ONLY can read primitive parameter value"); if (valueStr == "") return ""; if (valueStr.StartsWith("'")) return valueStr.Substring(1, valueStr.Length - 2); int intResult = -1; var intParseResult = int.TryParse(valueStr, out intResult); if (intParseResult) return intResult; else return valueStr; } /// /// version 3 combind DeviceProcessor, Communicator, Parser, Common into one project and namespace also adjusted. /// it'll break the old setting.xml, so here try to recover it by overwirte the old namespace and assembly name. /// /// /// internal static string Fallback_Version2_ResolveType_Compatbility(string version2TypeFullyQualifiedNameString) { if (Regex.IsMatch(version2TypeFullyQualifiedNameString, "^\\s{0,}(DeviceProcessor|Communicator)(\\..+)(\\1)\\s{0,}$")) { /* the old one likes(the content between the ""): * deviceProcessorType="DeviceProcessor.GenericDeviceProcessor`2[[System.Byte[]], [ProGauge_StartItaliana_Probe.MessageEntity.MessageBase, ProGauge_StartItaliana_Probe]], DeviceProcessor" * deviceProcessorType="DeviceProcessor.HalfDuplexActivePollingDeviceProcessor`2[[System.Byte[]], [OPW_VaporRecoveryOnlineWatch_DataCollector.DataCollectorMessageBase,OPW_VaporRecoveryOnlineWatch_DataCollector]], DeviceProcessor" * name="deviceHandlerType" value="ProGauge_StartItaliana_Probe.Handler,ProGauge_StartItaliana_Probe" * name="deviceHandlerType" value="LanTian_Pump_664_Or_886.PumpGroupHandler,LanTian_Pump_664_Or_886" * name="communicatorType" value="Communicator.ComPortCommunicator`1[[ProGauge_StartItaliana_Probe.MessageEntity.MessageBase,ProGauge_StartItaliana_Probe]],Communicator" * name="communicatorType" value="Communicator.TcpClientCommunicator`1[[VeederRoot_ATG_Console.MessageEntity.MessageBaseGeneric,VeederRoot_ATG_Console]],Communicator" */ version2TypeFullyQualifiedNameString = version2TypeFullyQualifiedNameString.Replace(" ", ""); return version2TypeFullyQualifiedNameString .Replace("DeviceProcessor.", "Edge.Core.Processor.") .Replace(",DeviceProcessor", ",Edge.Core") .Replace("Communicator.", "Edge.Core.Processor.Communicator.") .Replace(",Communicator", ",Edge.Core"); } else if (Regex.IsMatch(version2TypeFullyQualifiedNameString, "(DeviceProcessor|Communicator|Parser|Common),\\sCulture=\\w+?,\\sPublicKeyToken=\\w+")) { /* the old one likes: DeviceProcessor, Culture=neutral, PublicKeyToken=null */ return version2TypeFullyQualifiedNameString .Replace("DeviceProcessor", "Edge.Core") .Replace("Communicator", "Edge.Core") .Replace("Parser", "Edge.Core") .Replace("Common", "Edge.Core"); } else return version2TypeFullyQualifiedNameString; } } }