Major upgrade
This commit is contained in:
75
Source/Program/Common/Lib/EthernetSocketManager.cs
Normal file
75
Source/Program/Common/Lib/EthernetSocketManager.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
internal enum TcpClientNames
|
||||
{
|
||||
UUT_TEST_PORT
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores global events that any thread can use to wait on
|
||||
/// </summary>
|
||||
internal class EthernetSocketManager
|
||||
{
|
||||
private Dictionary<TcpClientNames, TcpClient> _tcpClientsDict = new Dictionary<TcpClientNames, TcpClient>();
|
||||
|
||||
/// <summary>
|
||||
/// The private constructor
|
||||
/// </summary>
|
||||
public EthernetSocketManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destructor
|
||||
/// </summary>
|
||||
~EthernetSocketManager()
|
||||
{
|
||||
foreach (KeyValuePair<TcpClientNames, TcpClient> item in _tcpClientsDict)
|
||||
{
|
||||
item.Value.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Tcp Client Socket
|
||||
/// </summary>
|
||||
public TcpClient GetTcpClient(TcpClientNames tcpClientName)
|
||||
{
|
||||
TcpClient tcpClient = null;
|
||||
|
||||
if (_tcpClientsDict.ContainsKey(tcpClientName))
|
||||
tcpClient = _tcpClientsDict[tcpClientName];
|
||||
|
||||
return tcpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Tcp Client Socket
|
||||
/// </summary>
|
||||
public void AddTcpClient(TcpClientNames tcpClientName, TcpClient tcpClient)
|
||||
{
|
||||
if (!_tcpClientsDict.ContainsKey(tcpClientName))
|
||||
_tcpClientsDict[tcpClientName] = tcpClient;
|
||||
}
|
||||
}
|
||||
}
|
||||
152
Source/Program/Common/Lib/EventGroup.cs
Normal file
152
Source/Program/Common/Lib/EventGroup.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that maps event array index to any event enumeration and wraps the WaitHandle.WaitAny() function
|
||||
/// Use case:
|
||||
/// When calling WaitHandle.WaitAny(EventArray), it only returns the index of the event in the array that is being signalled.
|
||||
/// Refering to an index of the array to know which event it is is not ideal. We want to be able to refer to an enumeration instead
|
||||
/// Usage:
|
||||
/// In class that uses this class, must define a enumeration
|
||||
/// public enum Events
|
||||
/// {
|
||||
/// EVENT1,
|
||||
/// EVENT2,
|
||||
/// EVENT3,
|
||||
/// EVENTN
|
||||
///
|
||||
/// // DO NOT change the name
|
||||
/// // This must be the last member in the enum
|
||||
/// EVENT_TIMED_OUT
|
||||
/// }
|
||||
/// Dictionary<Events, EventWaitHandle> dict = new Dictionary<Events, EventWaitHandle>();
|
||||
/// dict[Events.EVENT1] = new ManualResetEvent(false);
|
||||
/// dict[Events.EVENT2] = new AutoResetEvent(false);
|
||||
/// dict[Events.EVENT3] = new ManualResetEvent(false);
|
||||
/// dict[Events.EVENTN] = new AutoResetEvent(false);
|
||||
/// dict[Events.EVENT_TIMED_OUT] = null;
|
||||
///
|
||||
/// EventGroup<Events, EventWaitHandle> eventGroup = new EventGroup<Events, EventWaitHandle>(dict);
|
||||
///
|
||||
/// Events id = eventGroup.WaitAny([Optional_timeout]);
|
||||
///
|
||||
/// if (id == Events.EVENT_TIMED_OUT){} // only if timeout was specified
|
||||
/// if (id == Events.EVENT1){}
|
||||
///
|
||||
/// </summary>
|
||||
internal class EventGroup<T1, T2>
|
||||
{
|
||||
Dictionary<T1, T2> _eventDict = null;
|
||||
T2[] _eventArray = null;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
private EventGroup()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// The event enum passed in must be defined in the following format:
|
||||
/// public enum Events
|
||||
/// {
|
||||
/// EVENT1,
|
||||
/// EVENT2,
|
||||
/// EVENT3,
|
||||
/// EVENTN
|
||||
///
|
||||
/// // DO NOT change the name
|
||||
/// // This must be the last member in the enum
|
||||
/// EVENT_TIMED_OUT
|
||||
/// }
|
||||
/// </summary>
|
||||
/// <param name="eventDict">A dictionary that contains event enum that is associated to an event object</param>
|
||||
public EventGroup(Dictionary<T1, T2> eventDict)
|
||||
{
|
||||
if (eventDict == null)
|
||||
throw new Exception($"{nameof(eventDict)} cannot be null");
|
||||
|
||||
if (!eventDict.First().Key.GetType().IsEnum)
|
||||
{
|
||||
throw new Exception($"{nameof(eventDict)}'s key must be an enumerated type");
|
||||
}
|
||||
|
||||
// get the last element in the dictionary
|
||||
var element = eventDict.ElementAt(eventDict.Count - 1);
|
||||
|
||||
// check if the name of the last enum member is what we expect
|
||||
string actualNameOfLastEnumMember = ((Enum)Convert.ChangeType(element.Key, typeof(Enum))).ToString();
|
||||
|
||||
string expectedNameOfLastEnumMember = "EVENT_TIMED_OUT";
|
||||
if (actualNameOfLastEnumMember != expectedNameOfLastEnumMember)
|
||||
{
|
||||
throw new Exception($"Enum {element.Key.GetType().Name} must have {expectedNameOfLastEnumMember} as its last member. {nameof(eventDict)} must have {expectedNameOfLastEnumMember} as the last key in the dictionary");
|
||||
}
|
||||
|
||||
if (eventDict.First().Value.GetType().BaseType != typeof(EventWaitHandle))
|
||||
{
|
||||
throw new Exception($"{nameof(eventDict)}'s value must be ManualResetEvent or AutoResetEvent type");
|
||||
}
|
||||
_eventDict = eventDict;
|
||||
|
||||
_eventArray = new T2[_eventDict.Count - 1];
|
||||
|
||||
int index = 0;
|
||||
foreach (KeyValuePair<T1, T2> entry in _eventDict)
|
||||
{
|
||||
if (index < _eventDict.Count - 1)
|
||||
_eventArray[index++] = entry.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the enumerated event based on the index of the event in the event array that is being signalled
|
||||
/// </summary>
|
||||
/// <param name="timeoutMilliseconds">time out in milliseconds</param>
|
||||
public T1 WaitAny(int? timeoutMilliseconds = null)
|
||||
{
|
||||
int index = 0;
|
||||
T1 eventId = default;
|
||||
|
||||
if (timeoutMilliseconds == null)
|
||||
index = WaitHandle.WaitAny((EventWaitHandle[])Convert.ChangeType(_eventArray, typeof(EventWaitHandle[])));
|
||||
else
|
||||
index = WaitHandle.WaitAny((EventWaitHandle[])Convert.ChangeType(_eventArray, typeof(EventWaitHandle[])), (int)timeoutMilliseconds);
|
||||
|
||||
if (index == WaitHandle.WaitTimeout)
|
||||
{
|
||||
var element = _eventDict.ElementAt(_eventDict.Count - 1);
|
||||
eventId = element.Key;
|
||||
}
|
||||
else
|
||||
{
|
||||
var element = _eventDict.ElementAt(index);
|
||||
eventId = element.Key;
|
||||
}
|
||||
|
||||
return eventId;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Source/Program/Common/Lib/EventManager.Datatypes.cs
Normal file
33
Source/Program/Common/Lib/EventManager.Datatypes.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Partial class... defines all the types that this class needs
|
||||
/// </summary>
|
||||
internal partial class EventManager
|
||||
{
|
||||
public enum Events
|
||||
{
|
||||
GLOBAL_QUIT,
|
||||
UUT_POWER_ON,
|
||||
UUT_POWER_OFF,
|
||||
FATAL_FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Source/Program/Common/Lib/EventManager.cs
Normal file
55
Source/Program/Common/Lib/EventManager.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores global events that any thread can use to wait on
|
||||
/// </summary>
|
||||
internal partial class EventManager
|
||||
{
|
||||
private EventWaitHandle[] _events = new EventWaitHandle[Enum.GetValues(typeof(Events)).Cast<int>().Max() + 1];
|
||||
|
||||
/// <summary>
|
||||
/// The private constructor
|
||||
/// </summary>
|
||||
public EventManager()
|
||||
{
|
||||
for (int i = 0; i < _events.Count(); i++)
|
||||
{
|
||||
_events[i] = new ManualResetEvent(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement Indexer to obtain an event object
|
||||
/// </summary>
|
||||
/// <param name=""></param>
|
||||
/// <returns></returns>
|
||||
public EventWaitHandle this[Events eventId]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _events[(int)eventId];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Source/Program/Common/Lib/FileAndFolderManager.Datatypes.cs
Normal file
44
Source/Program/Common/Lib/FileAndFolderManager.Datatypes.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Partial class... defines all the types that this class needs
|
||||
/// </summary>
|
||||
internal partial class FileAndFolderManager
|
||||
{
|
||||
public enum Folders
|
||||
{
|
||||
// List data folder + its subfolders
|
||||
DATA,
|
||||
DATA_GENERAL,
|
||||
DATA_GENERAL_TEMP,
|
||||
DATA_TEST,
|
||||
|
||||
CONFIG,
|
||||
CONFIG_MEASUREMENT
|
||||
}
|
||||
|
||||
public enum Files
|
||||
{
|
||||
NLOG_TEMP,
|
||||
CABLE_SELF_TEST_RUN_LOG,
|
||||
TEST_RUN_LOG
|
||||
}
|
||||
}
|
||||
}
|
||||
227
Source/Program/Common/Lib/FileAndFolderManager.cs
Normal file
227
Source/Program/Common/Lib/FileAndFolderManager.cs
Normal file
@@ -0,0 +1,227 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using Raytheon.Common;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Partial class... this is the main class responsible for parsing config.ini in order
|
||||
/// to construct file paths and folder paths
|
||||
/// </summary>
|
||||
internal partial class FileAndFolderManager
|
||||
{
|
||||
private Dictionary<Folders, string> foldersDict = new Dictionary<Folders, string>();
|
||||
private Dictionary<Files, string> filesDict = new Dictionary<Files, string>();
|
||||
|
||||
private IConfigurationFile _programGeneralConfig;
|
||||
private IConfigurationFile _programSpecificConfig;
|
||||
private bool _isThereHardware;
|
||||
private string _configSubFolderName;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="programGeneralConfig">the UUT part number</param>
|
||||
public FileAndFolderManager(IConfigurationFile programGeneralConfig, out IConfigurationFile programSpecificConfig, bool isThereHardware, string configSubFolderName)
|
||||
{
|
||||
_programGeneralConfig = programGeneralConfig;
|
||||
_isThereHardware = isThereHardware;
|
||||
_configSubFolderName = configSubFolderName;
|
||||
|
||||
ConstructFolderPaths();
|
||||
CreateFolders();
|
||||
ConstructFilePaths();
|
||||
|
||||
programSpecificConfig = _programSpecificConfig;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destructor
|
||||
/// </summary>
|
||||
~FileAndFolderManager()
|
||||
{
|
||||
if (foldersDict.ContainsKey(Folders.DATA_TEST))
|
||||
{
|
||||
if (Directory.Exists(foldersDict[Folders.DATA_TEST]) && Directory.Exists(foldersDict[Folders.DATA]))
|
||||
{
|
||||
// delete all empty test folders
|
||||
if (foldersDict[Folders.DATA_TEST].Contains(foldersDict[Folders.DATA]))
|
||||
{
|
||||
string parentFolder = Path.GetFullPath(Path.Combine(foldersDict[Folders.DATA_TEST], ".."));
|
||||
|
||||
while (!String.Equals(parentFolder, foldersDict[Folders.DATA], StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string[] dirs = Directory.GetDirectories(parentFolder);
|
||||
|
||||
foreach (string dir in dirs)
|
||||
{
|
||||
if (Util.IsDirectoryEmpty(dir))
|
||||
Directory.Delete(dir, true);
|
||||
}
|
||||
|
||||
if (Util.IsDirectoryEmpty(parentFolder))
|
||||
Directory.Delete(parentFolder, true);
|
||||
|
||||
parentFolder = Path.GetFullPath(Path.Combine(parentFolder, ".."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ConstructTestFolder(UutInfo uutInfo, TestInfo testInfo)
|
||||
{
|
||||
string buildLevel = uutInfo.UutBuildLevel.ToString();
|
||||
if (uutInfo.UutBuildLevel == UutInfo.BuildLevel.NOT_SET)
|
||||
{
|
||||
buildLevel = "NO_UUT";
|
||||
}
|
||||
foldersDict[Folders.DATA_TEST] = Path.Combine(foldersDict[Folders.DATA], buildLevel, uutInfo.PartNumber,
|
||||
uutInfo.SerialNumber, testInfo.TestType.ToLower(), testInfo.TestStartDateTime.ToString("yyyy_MM_dd"),
|
||||
testInfo.TestName, testInfo.TestStartDateTime.ToString("HH_mm_ss"));
|
||||
|
||||
CreateFolders();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build folder paths so we can acccess them later
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private void ConstructFolderPaths()
|
||||
{
|
||||
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
string configHardwareOrSimSubFolderName = _programGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.SIM_CONFIG_FOLDER_NAME.ToString());
|
||||
if (_isThereHardware)
|
||||
configHardwareOrSimSubFolderName = _programGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.HARDWARE_CONFIG_FOLDER_NAME.ToString());
|
||||
|
||||
foldersDict[Folders.CONFIG] = Path.Combine(assemblyFolder, GeneralConstants.ConfigFolderName, configHardwareOrSimSubFolderName, _configSubFolderName);
|
||||
|
||||
string measurementConfigFolderName = _programGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.MEASUREMENT_CONFIG_FOLDER_NAME.ToString());
|
||||
foldersDict[Folders.CONFIG_MEASUREMENT] = Path.Combine(foldersDict[Folders.CONFIG], measurementConfigFolderName);
|
||||
|
||||
string programSpecificConfigFilePath = Path.Combine(GetFolder(Folders.CONFIG), _programGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.PROGRAM_SPECIFIC_CONFIG_FILE_NAME.ToString()));
|
||||
_programSpecificConfig = new ConfigurationFile(programSpecificConfigFilePath);
|
||||
|
||||
string dataRootPath;
|
||||
|
||||
// If primary drive exists on machine, all TE software files and folders should be located on that drive
|
||||
string drive = _programSpecificConfig.ReadValue(ProgramSpecificConfigIni.GENERAL.ToString(), ProgramSpecificConfigIni.PRIMARY_DRIVE.ToString());
|
||||
if (!Directory.Exists(drive))
|
||||
{
|
||||
drive = _programSpecificConfig.ReadValue(ProgramSpecificConfigIni.GENERAL.ToString(), ProgramSpecificConfigIni.SECONDARY_DRIVE.ToString());
|
||||
}
|
||||
dataRootPath = Path.Combine(drive, _programSpecificConfig.ReadValue(ProgramSpecificConfigIni.GENERAL.ToString(), ProgramSpecificConfigIni.DATA_BASE_FOLDER.ToString()));
|
||||
|
||||
if (!Path.IsPathRooted(dataRootPath))
|
||||
dataRootPath = Path.Combine(assemblyFolder, dataRootPath);
|
||||
else
|
||||
{
|
||||
Match regexMatch;
|
||||
|
||||
regexMatch = Regex.Match(dataRootPath, @"^([a-zA-Z]:\\).+", RegexOptions.IgnoreCase);
|
||||
|
||||
if (regexMatch.Success)
|
||||
{
|
||||
string driveLetter = regexMatch.Groups[1].Value;
|
||||
|
||||
if (!Directory.Exists(driveLetter))
|
||||
{
|
||||
|
||||
string err = $@"Invalid drive: {driveLetter}. Please provide a valid drive, ie C:\. File: {programSpecificConfigFilePath}. Section: {ProgramSpecificConfigIni.GENERAL.ToString()}. Key: {ProgramSpecificConfigIni.PRIMARY_DRIVE.ToString()} and Key: {ProgramSpecificConfigIni.SECONDARY_DRIVE.ToString()} were invalid drives.";
|
||||
|
||||
throw new Exception(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string err = $@"Invalid path: {dataRootPath}. Please specify desired folder name, i.e. Data. File: {programSpecificConfigFilePath}. Section: {ProgramSpecificConfigIni.GENERAL.ToString()}. Key: {ProgramSpecificConfigIni.DATA_BASE_FOLDER.ToString()}";
|
||||
|
||||
throw new Exception(err);
|
||||
}
|
||||
}
|
||||
|
||||
foldersDict[Folders.DATA] = Path.GetFullPath(dataRootPath);
|
||||
|
||||
string val = _programSpecificConfig.ReadValue(ProgramSpecificConfigIni.GENERAL.ToString(), ProgramSpecificConfigIni.DATA_GENERAL_FOLDER_NAME.ToString());
|
||||
foldersDict[Folders.DATA_GENERAL] = Path.Combine(dataRootPath, val);
|
||||
|
||||
val = _programSpecificConfig.ReadValue(ProgramSpecificConfigIni.GENERAL.ToString(), ProgramSpecificConfigIni.DATA_GENERAL_TEMP_FOLDER_NAME.ToString());
|
||||
foldersDict[Folders.DATA_GENERAL_TEMP] = Path.Combine(foldersDict[Folders.DATA_GENERAL], val);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We create all the necessary folders
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private void CreateFolders()
|
||||
{
|
||||
// create all the folders if they don't exist
|
||||
foreach (KeyValuePair<Folders, string> entry in foldersDict)
|
||||
{
|
||||
Directory.CreateDirectory(entry.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build file paths so we can acccess them later
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private void ConstructFilePaths()
|
||||
{
|
||||
string nlogFileNamePrefix = _programGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.NLOG_FILE_NAME_PREFIX.ToString());
|
||||
filesDict[Files.NLOG_TEMP] = Path.Combine(GetFolder(FileAndFolderManager.Folders.DATA_GENERAL_TEMP), _programGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.NLOG_FOLDER_NAME.ToString()), DateTime.Now.ToString("yyyy_MM_dd"), Util.GenerateUniqueFilenameUsingDateTime(nlogFileNamePrefix, "log"));
|
||||
filesDict[Files.CABLE_SELF_TEST_RUN_LOG] = Path.Combine(GetFolder(FileAndFolderManager.Folders.DATA_GENERAL), _programGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.CABLE_SELF_TEST_RUN_LOG_FILE_NAME.ToString()));
|
||||
filesDict[Files.TEST_RUN_LOG] = Path.Combine(GetFolder(FileAndFolderManager.Folders.DATA_GENERAL), _programGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.TEST_RUN_LOG_FILE_NAME.ToString()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the full folder path
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
/// <returns></returns>
|
||||
public string GetFolder(Folders folder)
|
||||
{
|
||||
if (foldersDict.ContainsKey(folder))
|
||||
{
|
||||
return foldersDict[folder];
|
||||
}
|
||||
else
|
||||
throw new Exception($"{folder.ToString()} is invalid");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the full file path
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetFile(Files file)
|
||||
{
|
||||
if (filesDict.ContainsKey(file))
|
||||
{
|
||||
return filesDict[file];
|
||||
}
|
||||
else
|
||||
throw new Exception($"{file.ToString()} is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Source/Program/Common/Lib/GeneralConstants.cs
Normal file
29
Source/Program/Common/Lib/GeneralConstants.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Define non-specific constants
|
||||
/// </summary>
|
||||
internal static class GeneralConstants
|
||||
{
|
||||
public const string ConfigFolderName = "ConfigFiles";
|
||||
|
||||
public const string ProgramGeneralConfigFilename = "ProgramGeneral.ini";
|
||||
}
|
||||
}
|
||||
307
Source/Program/Common/Lib/Util.cs
Normal file
307
Source/Program/Common/Lib/Util.cs
Normal file
@@ -0,0 +1,307 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
using System;
|
||||
using System.DirectoryServices;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using NLog;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides utility functions for other classes to use
|
||||
/// </summary>
|
||||
internal static class Util
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if directory is empty
|
||||
/// </summary>
|
||||
public static bool IsDirectoryEmpty(string path)
|
||||
{
|
||||
return !Directory.EnumerateFileSystemEntries(path).Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate random fractional part
|
||||
/// </summary>
|
||||
public static float GenerateRandomFraction()
|
||||
{
|
||||
Random rnd = new Random();
|
||||
int randNum = 0;
|
||||
const int minimum = 1;
|
||||
|
||||
randNum = rnd.Next(20);
|
||||
|
||||
if (randNum <= minimum)
|
||||
{
|
||||
randNum += minimum;
|
||||
}
|
||||
|
||||
return (float)(1.0 / (float)randNum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate unique file name
|
||||
/// Format: [Prefix]_YYYY_MM_DD_HH_MM_SS.[ext]
|
||||
/// </summary>
|
||||
public static string GenerateUniqueFilenameUsingDateTime(string prefix, string fileExtension)
|
||||
{
|
||||
string filename = prefix + "_" + DateTime.Now.ToString("yyyy_MM_dd") + "_" + DateTime.Now.ToString("HH_mm_ss");
|
||||
|
||||
if (fileExtension[0] != '.')
|
||||
{
|
||||
fileExtension = "." + fileExtension;
|
||||
}
|
||||
|
||||
filename += fileExtension;
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log Exception
|
||||
/// </summary>
|
||||
public static string LogException(Exception ex, ILogger logger)
|
||||
{
|
||||
string errorMsg = ex.Message;
|
||||
string stackTrace = ex.StackTrace;
|
||||
|
||||
Exception innerEx = ex.InnerException;
|
||||
while (innerEx != null)
|
||||
{
|
||||
errorMsg = innerEx.Message;
|
||||
stackTrace = innerEx.StackTrace + "\r\n" + stackTrace;
|
||||
|
||||
innerEx = innerEx.InnerException;
|
||||
}
|
||||
|
||||
logger.Error(errorMsg + "\r\n" + stackTrace);
|
||||
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auto format any numeric type to string
|
||||
/// </summary>
|
||||
/// <param name="wholeNumberMaxDigits">number of digits to display for the whole number before it display in scientific notation</param>
|
||||
public static string AutoFormatNumberToString<T>(T o, int wholeNumberMaxDigits = 3, int numDecimalPlaces = 2) where T : IConvertible
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Convert.ChangeType(o, typeof(double)) is double @double)
|
||||
{
|
||||
string originalStr = @double.ToString("G"); // Most compact
|
||||
string tempStr = originalStr;
|
||||
int indexOfDecimalPoint = tempStr.IndexOf(".");
|
||||
if (indexOfDecimalPoint == -1)
|
||||
tempStr += ".0";
|
||||
indexOfDecimalPoint = tempStr.IndexOf(".");
|
||||
int tempStrIndex = 0;
|
||||
int indexOfMinusSign = tempStr.IndexOf("-");
|
||||
if (indexOfMinusSign != -1)
|
||||
tempStrIndex = 1;
|
||||
int wholeNumberNumDigits = tempStr.Substring(tempStrIndex, indexOfDecimalPoint - tempStrIndex).Length;
|
||||
int fractionalNumDigits = tempStr.Substring(indexOfDecimalPoint + 1, tempStr.Length - (indexOfDecimalPoint + 1)).Length;
|
||||
if (wholeNumberNumDigits > wholeNumberMaxDigits || tempStr.IndexOf("E") != -1)
|
||||
{
|
||||
string decimalPlaces = String.Empty;
|
||||
for (int i = 1; i <= numDecimalPlaces; i++)
|
||||
{
|
||||
decimalPlaces += "#";
|
||||
}
|
||||
var custom = @double.ToString($"0.{decimalPlaces}E0").Replace("E+", "E");
|
||||
while (custom.Contains("E0")) custom = custom.Replace("E0", "E");
|
||||
while (custom.Contains("-0")) custom = custom.Replace("-0", "-");
|
||||
if ((@double < 0) && custom[0] != '-')
|
||||
{
|
||||
custom.Insert(0, "-");
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
else if (fractionalNumDigits > numDecimalPlaces)
|
||||
{
|
||||
return @double.ToString("0.##");
|
||||
}
|
||||
else
|
||||
{
|
||||
return originalStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return o.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get full name of windows user
|
||||
/// </summary>
|
||||
public static string GetWindowsUserFullName(string domain, string userName)
|
||||
{
|
||||
string name = "";
|
||||
|
||||
try
|
||||
{
|
||||
DirectoryEntry userEntry = new DirectoryEntry("WinNT://" + domain + "/" + userName + ",User");
|
||||
name = (string)userEntry.Properties["fullname"].Value;
|
||||
}
|
||||
catch
|
||||
{
|
||||
name = userName;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert struct to byte array
|
||||
/// </summary>
|
||||
public static byte[] StructToByteList<T>(T data)
|
||||
{
|
||||
int size = Marshal.SizeOf(data);
|
||||
|
||||
byte[] arr = new byte[size];
|
||||
|
||||
GCHandle h = default(GCHandle);
|
||||
|
||||
try
|
||||
{
|
||||
h = GCHandle.Alloc(arr, GCHandleType.Pinned);
|
||||
|
||||
Marshal.StructureToPtr(data, h.AddrOfPinnedObject(), false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (h.IsAllocated)
|
||||
{
|
||||
h.Free();
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert byte array to struct
|
||||
/// </summary>
|
||||
public static T ByteArrayToStruct<T>(byte[] array)
|
||||
{
|
||||
object obj;
|
||||
|
||||
GCHandle h = default(GCHandle);
|
||||
|
||||
try
|
||||
{
|
||||
h = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
|
||||
obj = Marshal.PtrToStructure(h.AddrOfPinnedObject(), typeof(T));
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (h.IsAllocated)
|
||||
{
|
||||
h.Free();
|
||||
}
|
||||
}
|
||||
|
||||
return (T)obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Two's Compliment Checksum
|
||||
/// </summary>
|
||||
public static byte GetTwosComplimentChecksum(byte[] array)
|
||||
{
|
||||
return (byte)(0x100u - ComputeSum(array));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add up all bytes in a byte array
|
||||
/// </summary>
|
||||
public static byte ComputeSum(byte[] array)
|
||||
{
|
||||
byte sum = 0;
|
||||
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
sum += array[i];
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display each byte in byte array as hex string
|
||||
/// </summary>
|
||||
public static string ByteArrayToHexString(byte[] bytes, int numBytes = -1)
|
||||
{
|
||||
StringBuilder Result = new StringBuilder(bytes.Length * 2);
|
||||
string HexAlphabet = "0123456789ABCDEF";
|
||||
|
||||
if (numBytes < 1)
|
||||
{
|
||||
numBytes = bytes.Length;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
{
|
||||
Result.Append("0x" + HexAlphabet[(int)(bytes[i] >> 4)]);
|
||||
Result.Append(HexAlphabet[(int)(bytes[i] & 0xF)] + " ");
|
||||
}
|
||||
|
||||
return Result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a variable of type TimeSpan, describe the time in days, hours, mins, seconds
|
||||
/// </summary>
|
||||
public static string DescribeTimeElapsed(TimeSpan ts)
|
||||
{
|
||||
string describe = "";
|
||||
|
||||
if (ts.Days > 0)
|
||||
describe += ts.Days.ToString() + " d";
|
||||
|
||||
if (ts.Hours > 0)
|
||||
{
|
||||
if (describe.Length > 0)
|
||||
describe += " ";
|
||||
describe += ts.Hours.ToString() + " h";
|
||||
}
|
||||
|
||||
if (ts.Minutes > 0)
|
||||
{
|
||||
if (describe.Length > 0)
|
||||
describe += " ";
|
||||
describe += ts.Minutes.ToString() + " m";
|
||||
}
|
||||
|
||||
if (ts.Seconds > 0)
|
||||
{
|
||||
if (describe.Length > 0)
|
||||
describe += " ";
|
||||
describe += ts.Seconds.ToString() + " s";
|
||||
}
|
||||
|
||||
if (describe.Length == 0)
|
||||
describe = "0 s";
|
||||
|
||||
return describe;
|
||||
}
|
||||
}
|
||||
}
|
||||
237
Source/Program/Common/Lib/XmlDocumentWrapper.cs
Normal file
237
Source/Program/Common/Lib/XmlDocumentWrapper.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// A XML Wrapper class to create/modify XML files
|
||||
/// </summary>
|
||||
internal class XmlDocumentWrapper
|
||||
{
|
||||
public enum AddNodePosition
|
||||
{
|
||||
First,
|
||||
Last
|
||||
}
|
||||
|
||||
private XmlDocument _xmlDoc = null;
|
||||
private string _xmlFilePath = String.Empty;
|
||||
private object _syncObj = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="xmlFilePath">XML file path</param>
|
||||
/// <param name="rootNodeName">name of the root node.</param>
|
||||
public XmlDocumentWrapper(string xmlFilePath, string rootNodeName = "root")
|
||||
{
|
||||
_xmlFilePath = xmlFilePath;
|
||||
CreateXmlDocument(rootNodeName);
|
||||
|
||||
_xmlDoc = new XmlDocument();
|
||||
_xmlDoc.Load(xmlFilePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create XML document if it doesn't exist
|
||||
/// </summary>
|
||||
private void CreateXmlDocument(string rootNodeName)
|
||||
{
|
||||
if (!File.Exists(_xmlFilePath))
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
XmlElement root = doc.CreateElement(rootNodeName);
|
||||
doc.AppendChild(root);
|
||||
|
||||
using (TextWriter sw = new StreamWriter(_xmlFilePath, false, Encoding.UTF8))
|
||||
{
|
||||
doc.Save(sw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save XML document to file
|
||||
/// </summary>
|
||||
public void SaveToFile()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
using (TextWriter sw = new StreamWriter(_xmlFilePath, false, Encoding.UTF8))
|
||||
{
|
||||
_xmlDoc.Save(sw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a node defined by {path}
|
||||
/// </summary>
|
||||
/// <param name="path">example: /root/node1/node2</param>
|
||||
/// <param name="attributesDict">a dictionary of [name,value] pairs</param>
|
||||
/// <param name="innerText">text of the node</param>
|
||||
public void AddNode(string path, Dictionary<string, string> attributesDict = null, string innerText = null, AddNodePosition addNodePosition = AddNodePosition.Last)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
XmlElement elem = (XmlElement)MakeXPath(_xmlDoc, path, addNodePosition);
|
||||
|
||||
if (!String.IsNullOrEmpty(innerText))
|
||||
elem.InnerText = innerText;
|
||||
|
||||
if (attributesDict != null)
|
||||
{
|
||||
List<XmlAttribute> attributes = new List<XmlAttribute>();
|
||||
|
||||
foreach (KeyValuePair<string, string> item in attributesDict)
|
||||
{
|
||||
XmlAttribute attr = _xmlDoc.CreateAttribute(item.Key);
|
||||
attr.Value = item.Value;
|
||||
|
||||
attributes.Add(attr);
|
||||
}
|
||||
|
||||
SetAttrSafe(elem, attributes.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a node
|
||||
/// </summary>
|
||||
public void RemoveNode(XmlNode node)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
node.ParentNode.RemoveChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change attributes and/or inner text of an existing node
|
||||
/// </summary>
|
||||
public void ChangeNode(XmlNode node, Dictionary<string, string> attributesDict = null, string innerText = null)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(innerText))
|
||||
node.InnerText = innerText;
|
||||
|
||||
if (attributesDict != null)
|
||||
{
|
||||
List<XmlAttribute> attributes = new List<XmlAttribute>();
|
||||
|
||||
foreach (KeyValuePair<string, string> item in attributesDict)
|
||||
{
|
||||
XmlAttribute attr = _xmlDoc.CreateAttribute(item.Key);
|
||||
attr.Value = item.Value;
|
||||
|
||||
attributes.Add(attr);
|
||||
}
|
||||
|
||||
SetAttrSafe(node, attributes.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the first node in {path}
|
||||
/// Useful for iterating through the sibling nodes to find the node with a specific attribute so we can modify the node
|
||||
/// </summary>
|
||||
/// <param name="path">example: /root/node1/node2</param>
|
||||
public XmlNode GetNode(string path)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
return _xmlDoc.SelectSingleNode(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all the nodes matching the path
|
||||
/// Useful for iterating through the matched nodes
|
||||
/// </summary>
|
||||
/// <param name="path">example: /root/node1/node2</param>
|
||||
public XmlNodeList GetNodes(string path)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
return _xmlDoc.SelectNodes(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set attribute
|
||||
/// </summary>
|
||||
private void SetAttrSafe(XmlNode node, XmlAttribute[] attrList)
|
||||
{
|
||||
foreach (var attr in attrList)
|
||||
{
|
||||
if (node.Attributes[attr.Name] != null)
|
||||
{
|
||||
node.Attributes[attr.Name].Value = attr.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Attributes.Append(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a node using {xpath}
|
||||
/// </summary>
|
||||
/// <param name="xpath">example: /root/node1/node2</param>
|
||||
private XmlNode MakeXPath(XmlDocument doc, string xpath, AddNodePosition addNodePosition)
|
||||
{
|
||||
return MakeXPath(doc, doc as XmlNode, xpath, addNodePosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterate through each node in {xpath} and create them
|
||||
/// </summary>
|
||||
private XmlNode MakeXPath(XmlDocument doc, XmlNode parent, string xpath, AddNodePosition addNodePosition)
|
||||
{
|
||||
// grab the next node name in the xpath; or return parent if empty
|
||||
string[] partsOfXPath = xpath.Trim('/').Split('/');
|
||||
string nextNodeInXPath = partsOfXPath.First();
|
||||
if (string.IsNullOrEmpty(nextNodeInXPath))
|
||||
return parent;
|
||||
|
||||
// get or create the node from the name
|
||||
XmlNode node = parent.SelectSingleNode(nextNodeInXPath);
|
||||
if (partsOfXPath.Length == 1)
|
||||
{
|
||||
if (addNodePosition == AddNodePosition.Last)
|
||||
node = parent.AppendChild(doc.CreateElement(nextNodeInXPath));
|
||||
else
|
||||
node = parent.PrependChild(doc.CreateElement(nextNodeInXPath));
|
||||
}
|
||||
|
||||
// rejoin the remainder of the array as an xpath expression and recurse
|
||||
string rest = String.Join("/", partsOfXPath.Skip(1).ToArray());
|
||||
return MakeXPath(doc, node, rest, addNodePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user