LegacySettingsXmlFileLoader.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. using Edge.Core.Configuration;
  2. using Microsoft.Extensions.DependencyInjection;
  3. using Microsoft.Extensions.Logging;
  4. using Microsoft.Extensions.Logging.Abstractions;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Text.RegularExpressions;
  10. using System.Threading.Tasks;
  11. namespace Edge.Core.Processor.Dispatcher
  12. {
  13. public class LegacySettingsXmlFileLoader : IProcessorLoader
  14. {
  15. protected IServiceProvider services;
  16. protected static ILogger mainLogger = NullLogger.Instance;
  17. public LegacySettingsXmlFileLoader(IServiceProvider services)
  18. {
  19. this.services = services;
  20. var loggerFactory = services.GetRequiredService<ILoggerFactory>();
  21. mainLogger = loggerFactory.CreateLogger("Main");
  22. }
  23. public IEnumerable<ProcessorInstanceOperatingResult> CreateAll()
  24. {
  25. mainLogger.LogInformation("Use LegacySettingsXmlFileLoader for Processor Meta Config.");
  26. Console.WriteLine("Use LegacySettingsXmlFileLoader for Processor Meta Config.");
  27. var configurator = this.services.GetRequiredService<Configurator>();
  28. var processorConfigs = configurator.DeviceProcessorConfiguration.Processor.OrderBy(pc => pc.Name).ToList();
  29. mainLogger.LogInformation("==============Instantiate Processors (total: " + processorConfigs.Count() + ")==============");
  30. Console.WriteLine();
  31. Console.WriteLine("==============Instantiate Processors (total: " + processorConfigs.Count() + ")==============");
  32. //List<IProcessor> processorInstances = new List<IProcessor>();
  33. var createResults = new List<ProcessorInstanceOperatingResult>();
  34. for (int i = 0; i < processorConfigs.Count; i++)
  35. {
  36. var pc = processorConfigs[i];
  37. try
  38. {
  39. mainLogger.LogInformation("[" + i + "]: " + pc.Name + ", " + pc.DeviceProcessorType);
  40. Console.WriteLine("[" + i + "]: " + pc.Name + ", " + pc.DeviceProcessorType);
  41. var parameters = pc.Parameter;//.Cast<DeviceProcessorParameter>();
  42. foreach (var para in parameters)
  43. {
  44. mainLogger.LogInformation(" " + para.Name + " : " + para.Value);
  45. //Console.WriteLine(" " + para.Name + " : " + para.Value);
  46. }
  47. var processorInstance =
  48. ConstructComplexType_Xml_String(pc.DeviceProcessorType, pc.ConstructorArg, parameters, services) as IProcessor;
  49. processorInstance.MetaConfigName = pc.Name;
  50. createResults.Add(new ProcessorInstanceOperatingResult()
  51. {
  52. MetaConfig = new ProcessorMetaConfig()
  53. {
  54. Name = pc.Name,
  55. Activated = true,
  56. SourceEndpointFullTypeStr = pc.DeviceProcessorType,
  57. Type = processorInstance is IAppProcessor ? ProcessorTypeEnum.AppProcessor : ProcessorTypeEnum.DeviceProcessor,
  58. Description = "Current using Legacy Settings XmlFile mode, so this is a fake ProcessorMetaConfig"
  59. },
  60. //Description = "Legacy Settings XmlFile mode for instantiate a processor, and succeed",
  61. Succeed = true,
  62. ProcessorInstance = processorInstance,
  63. //MetaConfig = mc,
  64. });
  65. }
  66. catch (Exception eee)
  67. {
  68. createResults.Add(new ProcessorInstanceOperatingResult()
  69. {
  70. MetaConfig = new ProcessorMetaConfig()
  71. {
  72. Name = pc.Name,
  73. Activated = true,
  74. SourceEndpointFullTypeStr = pc.DeviceProcessorType,
  75. Description = "Current using Legacy Settings XmlFile mode, so this is a fake ProcessorMetaConfig"
  76. },
  77. //Description = "Legacy Settings XmlFile mode for instantiate a processor, but failed",
  78. Succeed = false,
  79. //MetaConfig = mc,
  80. FailedReason = eee.ToString()
  81. });
  82. mainLogger.LogError(" - Failed for instantiate: " + pc.Name + Environment.NewLine + " " + eee.ToString());
  83. Console.BackgroundColor = ConsoleColor.Red;
  84. Console.ForegroundColor = ConsoleColor.Black;
  85. Console.WriteLine(" - Failed for instantiate: " + pc.Name + Environment.NewLine + " " + eee.ToString().Substring(0, 90) + "...");
  86. Console.ResetColor();
  87. }
  88. }
  89. mainLogger.LogInformation("==============Instantiate Processors End==============");
  90. Console.WriteLine("==============Instantiate Processors End==============");
  91. return createResults;
  92. }
  93. public IProcessor Create(string configName)
  94. {
  95. if (string.IsNullOrEmpty(configName)) throw new ArgumentException(nameof(configName));
  96. var configurator = this.services.GetRequiredService<Configurator>();
  97. var processorConfig = configurator.DeviceProcessorConfiguration.Processor.First(settingsXmlConfig => settingsXmlConfig.Name == configName);
  98. var p =
  99. ConstructComplexType_Xml_String(
  100. processorConfig.DeviceProcessorType,
  101. processorConfig.ConstructorArg,
  102. processorConfig.Parameter, services) as IProcessor;
  103. p.MetaConfigName = processorConfig.Name;
  104. return p;
  105. }
  106. /// <summary>
  107. ///
  108. /// </summary>
  109. /// <param name="typeFullyQualifiedNameString">nameSpace.ClassA, AssemblyFileName</param>
  110. /// <param name="constrStrFromConfig"></param>
  111. /// <param name="parameters"></param>
  112. /// <param name="services"></param>
  113. /// <returns></returns>
  114. protected virtual dynamic ConstructComplexType_Xml_String(string typeFullyQualifiedNameString, string constrStrFromConfig, IEnumerable<ProcessorParameter> parameters, IServiceProvider services)
  115. {
  116. Type processorType = Type.GetType(typeFullyQualifiedNameString);
  117. if (processorType == null)
  118. {
  119. var fallbackToVersion2NameString = Fallback_Version2_ResolveType_Compatbility(typeFullyQualifiedNameString);
  120. processorType = Type.GetType(fallbackToVersion2NameString);
  121. if (processorType == null)
  122. throw new ArgumentException("Could not resolve type: " + typeFullyQualifiedNameString);
  123. else
  124. typeFullyQualifiedNameString = fallbackToVersion2NameString;
  125. }
  126. if (string.IsNullOrEmpty(constrStrFromConfig))
  127. {
  128. try
  129. {
  130. //now only support injecting one parameter.
  131. var injectingCtor = processorType.GetConstructors().FirstOrDefault(c => c.GetParameters().Length == 1);
  132. if (injectingCtor != null
  133. && injectingCtor.GetParameters().First().ParameterType == typeof(IServiceProvider))
  134. {
  135. mainLogger.LogTrace("Constructing instance(with 1 param ctor and empty param from config) with type: " + processorType.Name);
  136. mainLogger.LogTrace(" - ctor parameter with name: " + injectingCtor.GetParameters().First().Name + " is type IServiceProvider, will injecting");
  137. var injectedInstance = Activator.CreateInstance(processorType, new object[] { services });
  138. mainLogger.LogTrace(" Done constructing instance(with 1 param ctor and empty param from config) with type: " + processorType.Name);
  139. return injectedInstance;
  140. }
  141. mainLogger.LogTrace("Constructing instance(with empty param ctor and empty param from config) with type: " + processorType.Name);
  142. var parameterlessInstance = Activator.CreateInstance(processorType);
  143. mainLogger.LogTrace(" Done constructing instance(with empty param ctor and empty param from config) with type: " + processorType.Name);
  144. return parameterlessInstance;
  145. }
  146. catch (Exception exxx)
  147. {
  148. //mainLogger.LogError();
  149. throw new InvalidOperationException("CreateInstance(with empty ctor) for: "
  150. + typeFullyQualifiedNameString + " failed, " + Environment.NewLine + " exception detail: " + exxx);
  151. }
  152. }
  153. else
  154. {
  155. List<object> cArgsFromConfig = new List<object>();
  156. var constructorArgStrings = constrStrFromConfig.Replace("\r", "").Replace("\n", "").Split(',').Select(s => s.Trim()).ToArray();
  157. for (int i = 0; i < constructorArgStrings.Length; i++)
  158. {
  159. var argStr = constructorArgStrings[i];
  160. try
  161. {
  162. if (!argStr.StartsWith("ref:"))
  163. {
  164. cArgsFromConfig.Add(readPrimitiveParameterValue(argStr));
  165. }
  166. else if (argStr.StartsWith("ref:"))
  167. {
  168. var refTo = argStr.Substring(4);
  169. // quick ref
  170. if (refTo.Contains(':'))
  171. {
  172. var quickRefValuePart = refTo.Split(':').Last();
  173. cArgsFromConfig.Add(readPrimitiveParameterValue(quickRefValuePart));
  174. }
  175. else
  176. {
  177. var refParameter = parameters.First(p => p.Name == refTo);
  178. if (!refParameter.Complex)
  179. {
  180. cArgsFromConfig.Add(readPrimitiveParameterValue(refParameter.Value));
  181. }
  182. else
  183. {
  184. var complexArg = ConstructComplexType_Xml_String(refParameter.Value, refParameter.ConstructorArg, parameters, services);
  185. cArgsFromConfig.Add(complexArg);
  186. }
  187. }
  188. }
  189. }
  190. catch (Exception exxx)
  191. {
  192. throw new InvalidOperationException("failed for parse constructor arg[" + i + "]: " + argStr
  193. + " " + Environment.NewLine + " for type: " + processorType.Name
  194. + " " + Environment.NewLine + " detail: " + exxx);
  195. }
  196. //else if (argStr.StartsWith("refIdArray("))
  197. //{
  198. // var idsString = argStr.Skip("refIdArray(".Length).TakeWhile(p => p != ')')
  199. // .Select(c => c.ToString()).Aggregate((acc, n) => acc + n);
  200. // var output = processors.Where(p => idsString.Trim().Split('|').ToList().Contains(p.Id.ToString()));
  201. // cArgs.Add(output);
  202. //}
  203. }
  204. //var cc = deviceProcessorType.GetConstructors();
  205. try
  206. {
  207. mainLogger.LogTrace("Constructing instance(with multiple param ctor and "
  208. + cArgsFromConfig.Count + " param from config) with type: " + processorType.Name);
  209. //now only support injecting one parameter.
  210. var injectingCtor = processorType.GetConstructors().FirstOrDefault(c => c.GetParameters().Length == cArgsFromConfig.Count + 1);
  211. //for(int c=0;c<injectingCtors.Count())
  212. //{
  213. if (injectingCtor != null)
  214. {
  215. var ctParams = injectingCtor.GetParameters();
  216. for (int i = 0; i < ctParams.Length; i++)
  217. {
  218. var param = ctParams[i];
  219. if (param.ParameterType == typeof(IServiceProvider))
  220. {
  221. mainLogger.LogTrace(" - ctor parameter with name: " + ctParams[i].Name + " is type IServiceProvider, will injecting");
  222. cArgsFromConfig.Insert(i, services);
  223. }
  224. }
  225. }
  226. //}
  227. var s = Activator.CreateInstance(processorType, cArgsFromConfig.ToArray());
  228. mainLogger.LogTrace(" Done constructing instance with type: " + processorType.Name);
  229. return s;
  230. }
  231. catch (Exception exxx)
  232. {
  233. throw new InvalidOperationException("CreateInstance(with ctor args: "
  234. + cArgsFromConfig.Select(c => c.ToString()).Aggregate((acc, n) => acc + ", " + n) + ") for: " + processorType.Name + " failed, \r\n exception detail: " + exxx);
  235. }
  236. }
  237. }
  238. protected virtual object readPrimitiveParameterValue(string valueStr)
  239. {
  240. if (valueStr.StartsWith("ref:")) throw new ArgumentException("ONLY can read primitive parameter value");
  241. if (valueStr == "") return "";
  242. if (valueStr.StartsWith("'")) return valueStr.Substring(1, valueStr.Length - 2);
  243. int intResult = -1;
  244. var intParseResult = int.TryParse(valueStr, out intResult);
  245. if (intParseResult) return intResult;
  246. else return valueStr;
  247. }
  248. /// <summary>
  249. /// version 3 combind DeviceProcessor, Communicator, Parser, Common into one project and namespace also adjusted.
  250. /// it'll break the old setting.xml, so here try to recover it by overwirte the old namespace and assembly name.
  251. /// </summary>
  252. /// <param name="version2TypeFullyQualifiedNameString"></param>
  253. /// <returns></returns>
  254. internal static string Fallback_Version2_ResolveType_Compatbility(string version2TypeFullyQualifiedNameString)
  255. {
  256. if (Regex.IsMatch(version2TypeFullyQualifiedNameString,
  257. "^\\s{0,}(DeviceProcessor|Communicator)(\\..+)(\\1)\\s{0,}$"))
  258. {
  259. /* the old one likes(the content between the ""):
  260. * deviceProcessorType="DeviceProcessor.GenericDeviceProcessor`2[[System.Byte[]], [ProGauge_StartItaliana_Probe.MessageEntity.MessageBase, ProGauge_StartItaliana_Probe]], DeviceProcessor"
  261. * deviceProcessorType="DeviceProcessor.HalfDuplexActivePollingDeviceProcessor`2[[System.Byte[]], [OPW_VaporRecoveryOnlineWatch_DataCollector.DataCollectorMessageBase,OPW_VaporRecoveryOnlineWatch_DataCollector]], DeviceProcessor"
  262. * name="deviceHandlerType" value="ProGauge_StartItaliana_Probe.Handler,ProGauge_StartItaliana_Probe"
  263. * name="deviceHandlerType" value="LanTian_Pump_664_Or_886.PumpGroupHandler,LanTian_Pump_664_Or_886"
  264. * name="communicatorType" value="Communicator.ComPortCommunicator`1[[ProGauge_StartItaliana_Probe.MessageEntity.MessageBase,ProGauge_StartItaliana_Probe]],Communicator"
  265. * name="communicatorType" value="Communicator.TcpClientCommunicator`1[[VeederRoot_ATG_Console.MessageEntity.MessageBaseGeneric,VeederRoot_ATG_Console]],Communicator"
  266. */
  267. version2TypeFullyQualifiedNameString = version2TypeFullyQualifiedNameString.Replace(" ", "");
  268. return version2TypeFullyQualifiedNameString
  269. .Replace("DeviceProcessor.", "Edge.Core.Processor.")
  270. .Replace(",DeviceProcessor", ",Edge.Core")
  271. .Replace("Communicator.", "Edge.Core.Processor.Communicator.")
  272. .Replace(",Communicator", ",Edge.Core");
  273. }
  274. else if (Regex.IsMatch(version2TypeFullyQualifiedNameString,
  275. "(DeviceProcessor|Communicator|Parser|Common),\\sCulture=\\w+?,\\sPublicKeyToken=\\w+"))
  276. {
  277. /* the old one likes: DeviceProcessor, Culture=neutral, PublicKeyToken=null */
  278. return version2TypeFullyQualifiedNameString
  279. .Replace("DeviceProcessor", "Edge.Core")
  280. .Replace("Communicator", "Edge.Core")
  281. .Replace("Parser", "Edge.Core")
  282. .Replace("Common", "Edge.Core");
  283. }
  284. else
  285. return version2TypeFullyQualifiedNameString;
  286. }
  287. }
  288. }