From 4c6775b48d896505c73b7060be56c64a9ac7e712 Mon Sep 17 00:00:00 2001 From: Simon Gockner Date: Wed, 12 Feb 2020 11:53:13 +0100 Subject: [PATCH] #10: add dataHandling --- .../DataHandling/Cache/XmlDataHandlerCache.cs | 132 ++++++++++++++ .../Cache/XmlDataHandlerCacheEntry.cs | 41 +++++ .../Cache/XmlDataHandlerCachePropertyEntry.cs | 41 +++++ GBase/DataHandling/XmlDataHandler.cs | 160 +++++++++++++++++ GBase/DataHandling/XmlDataReader.cs | 104 +++++++++++ GBase/DataHandling/XmlDataWriter.cs | 168 ++++++++++++++++++ .../DataHandling/Cache/IDataHandlerCache.cs | 46 +++++ .../Cache/IDataHandlerCacheEntry.cs | 25 +++ .../Cache/IDataHandlerCachePropertyEntry.cs | 29 +++ GBase/Interfaces/DataHandling/IDataHandler.cs | 63 +++++++ GBase/Interfaces/DataHandling/IDataReader.cs | 33 ++++ GBase/Interfaces/DataHandling/IDataWriter.cs | 44 +++++ .../IXmlDataHandlerCacheEntryFactory.cs | 13 ++ .../Factories/IXmlDataHandlerCacheFactory.cs | 11 ++ ...XmlDataHandlerCachePropertyEntryFactory.cs | 11 ++ .../Xml/Cache/IXmlDataHandlerCache.cs | 16 ++ .../Xml/Cache/IXmlDataHandlerCacheEntry.cs | 16 ++ .../IXmlDataHandlerCachePropertyEntry.cs | 16 ++ .../Xml/Factories/IXmlDataHandlerFactory.cs | 11 ++ .../Xml/Factories/IXmlDataReaderFactory.cs | 11 ++ .../Xml/Factories/IXmlDataWriterFactory.cs | 11 ++ .../DataHandling/Xml/IXmlDataHandler.cs | 14 ++ .../DataHandling/Xml/IXmlDataReader.cs | 14 ++ .../DataHandling/Xml/IXmlDataWriter.cs | 14 ++ 24 files changed, 1044 insertions(+) create mode 100644 GBase/DataHandling/Cache/XmlDataHandlerCache.cs create mode 100644 GBase/DataHandling/Cache/XmlDataHandlerCacheEntry.cs create mode 100644 GBase/DataHandling/Cache/XmlDataHandlerCachePropertyEntry.cs create mode 100644 GBase/DataHandling/XmlDataHandler.cs create mode 100644 GBase/DataHandling/XmlDataReader.cs create mode 100644 GBase/DataHandling/XmlDataWriter.cs create mode 100644 GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs create mode 100644 GBase/Interfaces/DataHandling/Cache/IDataHandlerCacheEntry.cs create mode 100644 GBase/Interfaces/DataHandling/Cache/IDataHandlerCachePropertyEntry.cs create mode 100644 GBase/Interfaces/DataHandling/IDataHandler.cs create mode 100644 GBase/Interfaces/DataHandling/IDataReader.cs create mode 100644 GBase/Interfaces/DataHandling/IDataWriter.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheEntryFactory.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheFactory.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCachePropertyEntryFactory.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCache.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCacheEntry.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCachePropertyEntry.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataHandlerFactory.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataReaderFactory.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataWriterFactory.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/IXmlDataHandler.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/IXmlDataReader.cs create mode 100644 GBase/Interfaces/DataHandling/Xml/IXmlDataWriter.cs diff --git a/GBase/DataHandling/Cache/XmlDataHandlerCache.cs b/GBase/DataHandling/Cache/XmlDataHandlerCache.cs new file mode 100644 index 0000000..ce3b125 --- /dev/null +++ b/GBase/DataHandling/Cache/XmlDataHandlerCache.cs @@ -0,0 +1,132 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using GBase.Interfaces.DataHandling.Cache; +using GBase.Interfaces.DataHandling.Xml; +using GBase.Interfaces.DataHandling.Xml.Cache; +using GBase.Interfaces.DataHandling.Xml.Cache.Factories; + +namespace GBase.DataHandling.Cache +{ + /// + /// An interface for the + /// + public class XmlDataHandlerCache : IXmlDataHandlerCache + { + private readonly IXmlDataReader _xmlDataReader; + private readonly IXmlDataHandlerCacheEntryFactory _xmlDataHandlerCacheEntryFactory; + private readonly IXmlDataHandlerCachePropertyEntryFactory _xmlDataHandlerCachePropertyEntryFactory; + + private readonly List _cache; + + /// + /// An interface for the + /// + /// The + /// A factory for the + /// A factory for the + public XmlDataHandlerCache(IXmlDataReader xmlDataReader, + IXmlDataHandlerCacheEntryFactory xmlDataHandlerCacheEntryFactory, + IXmlDataHandlerCachePropertyEntryFactory xmlDataHandlerCachePropertyEntryFactory) + { + _xmlDataReader = xmlDataReader; + _xmlDataHandlerCacheEntryFactory = xmlDataHandlerCacheEntryFactory; + _xmlDataHandlerCachePropertyEntryFactory = xmlDataHandlerCachePropertyEntryFactory; + + _cache = new List(); + } + + /// + /// Set the value for the given property + /// + /// The that implements the property + /// The of the property + /// The name of the property + /// The value to set + /// If true an existing value is overwritten, if false an additional value is added + /// A to await + public async Task SetValue(string propertyName, TProperty value, bool overwrite) //TODO: async? + { + IXmlDataHandlerCacheEntry entry = _cache.FirstOrDefault(e => e.Type == typeof(T)); + if (entry != null) //entry exists + { + IDataHandlerCachePropertyEntry property = entry.Properties.FirstOrDefault(p => p.PropertyName.Equals(propertyName)); + if (property != null) //property entry exists + { + if (overwrite) + property.Values[0] = value; //if overwrite is true, overwrite first value + else if (property.Values.Any(v => v.Equals(value))) //same value already exists for this property + { + object sameValue = property.Values.First(v => v.Equals(value)); + if (property.Values.IndexOf(sameValue) == 0) //if it is the first item already, do nothing + return; + + property.Values.Remove(sameValue); //remove it + property.Values.Insert(0, sameValue); //insert it at the first position + } + else //overwrite is false and no equal value exists + property.Values.Insert(0, value); //insert value at the first position + } + else //property entry doesn't exist + entry.Properties.Add(_xmlDataHandlerCachePropertyEntryFactory.Create(propertyName, value)); //create new property entry + } + else //entry doesn't exist + _cache.Add(_xmlDataHandlerCacheEntryFactory.Create(typeof(T), propertyName, value)); //create new entry + } + + /// + /// Remove the value for the given property + /// + /// The of the property + /// The of the property + /// The name of the property + /// The value to set + /// A to await + public async Task TryRemoveValue(string propertyName, TProperty value) //TODO: async? + { + IXmlDataHandlerCacheEntry entry = _cache.FirstOrDefault(e => e.Type == typeof(T)); + IDataHandlerCachePropertyEntry property = entry?.Properties.FirstOrDefault(p => p.PropertyName.Equals(propertyName)); + object valueToRemove = property?.Values.FirstOrDefault(v => v.Equals(value)); + if (valueToRemove == null) + return; + + property.Values.Remove(valueToRemove); + } + + /// + /// Try to get values from the cache for the given property + /// + /// The that implements the property + /// The of the property + /// The name of the property + /// An with all the values for the property + public async Task> TryGetValues(string propertyName) + { + IXmlDataHandlerCacheEntry entry = _cache.FirstOrDefault(e => e.Type == typeof(T)); + IDataHandlerCachePropertyEntry property = entry?.Properties.FirstOrDefault(p => p.PropertyName.Equals(propertyName)); + if (property == null) + return null; + + if (!property.IsInitialized) //initialize property by reading the values from the xml + { + List values = (await _xmlDataReader.Read(propertyName))?.ToList(); + if (values != null) + { + foreach (TProperty value in values.Where(value => !property.Values.Any(v => v.Equals(value)))) + { + property.Values.Add(value); //only add values that don't already exist + } + } + + property.IsInitialized = true; + } + + return property.Values.Cast(); + } + } +} \ No newline at end of file diff --git a/GBase/DataHandling/Cache/XmlDataHandlerCacheEntry.cs b/GBase/DataHandling/Cache/XmlDataHandlerCacheEntry.cs new file mode 100644 index 0000000..850fb95 --- /dev/null +++ b/GBase/DataHandling/Cache/XmlDataHandlerCacheEntry.cs @@ -0,0 +1,41 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Collections.Generic; +using GBase.Interfaces.DataHandling.Cache; +using GBase.Interfaces.DataHandling.Xml.Cache; +using GBase.Interfaces.DataHandling.Xml.Cache.Factories; + +namespace GBase.DataHandling.Cache +{ + /// + /// Entry for the + /// + public class XmlDataHandlerCacheEntry : IXmlDataHandlerCacheEntry + { + /// + /// Entry for the + /// + /// The that implements the property + /// The name of the property + /// The value of the property + /// Factory for the + public XmlDataHandlerCacheEntry(Type type, string propertyName, object value, IXmlDataHandlerCachePropertyEntryFactory xmlDataHandlerCachePropertyEntryFactory) + { + Type = type; + Properties = new List() { xmlDataHandlerCachePropertyEntryFactory.Create(propertyName, value) }; + } + + /// + /// The of the + /// + public Type Type { get; } + + /// + /// The properties of the + /// + public List Properties { get; } + } +} \ No newline at end of file diff --git a/GBase/DataHandling/Cache/XmlDataHandlerCachePropertyEntry.cs b/GBase/DataHandling/Cache/XmlDataHandlerCachePropertyEntry.cs new file mode 100644 index 0000000..c1a7828 --- /dev/null +++ b/GBase/DataHandling/Cache/XmlDataHandlerCachePropertyEntry.cs @@ -0,0 +1,41 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System.Collections.Generic; +using GBase.Interfaces.DataHandling.Xml.Cache; + +namespace GBase.DataHandling.Cache +{ + /// + /// A property entry for the + /// + public class XmlDataHandlerCachePropertyEntry : IXmlDataHandlerCachePropertyEntry + { + /// + /// A property entry for the + /// + /// The name of the property + /// The value of the property + public XmlDataHandlerCachePropertyEntry(string propertyName, object value) + { + PropertyName = propertyName; + Values = new List() { value }; + } + + /// + /// The name of the property + /// + public string PropertyName { get; } + + /// + /// This property is initialized in the + /// + public bool IsInitialized { get; set; } + + /// + /// The values of the property + /// + public List Values { get; } + } +} \ No newline at end of file diff --git a/GBase/DataHandling/XmlDataHandler.cs b/GBase/DataHandling/XmlDataHandler.cs new file mode 100644 index 0000000..f0926c6 --- /dev/null +++ b/GBase/DataHandling/XmlDataHandler.cs @@ -0,0 +1,160 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using GBase.Interfaces.DataHandling; +using GBase.Interfaces.DataHandling.Xml; +using GBase.Interfaces.DataHandling.Xml.Cache; +using GBase.Interfaces.DataHandling.Xml.Cache.Factories; +using GBase.Interfaces.DataHandling.Xml.Factories; + +namespace GBase.DataHandling +{ + //TODO: access cache asynchronously? + + /// + /// A that handles its data in an xml file + /// + public class XmlDataHandler : IXmlDataHandler + { + /// + /// The element name of the value element + /// + public const string VALUE_ELEMENT_NAME = "Value"; + + /// + /// The attribute name of the value attribute + /// + public const string VALUE_TYPE_ATTRIBUTE_NAME = "type"; + + private readonly IXmlDataReader _xmlDataReader; + private readonly IXmlDataWriter _xmlDataWriter; + + private readonly IXmlDataHandlerCache _cache; + + private bool _isInitialized; + private bool _overwrite; + + /// + /// A that handles its data in an xml file + /// + /// The path to the xml file + /// The root element name of the xml file + /// The factory + /// The factory + /// The factory + public XmlDataHandler(string path, + string rootElementName, + IXmlDataReaderFactory xmlDataReaderFactory, + IXmlDataWriterFactory xmlDataWriterFactory, + IXmlDataHandlerCacheFactory xmlDataHandlerCacheFactory) + { + _xmlDataWriter = xmlDataWriterFactory.Create(path, rootElementName); + _xmlDataReader = xmlDataReaderFactory.Create(path); + + _cache = xmlDataHandlerCacheFactory.Create(_xmlDataReader); + } + + /// + /// Initialize the + /// + /// If true an existing value is overwritten, if false an additional value is added + /// A to cancel the async operation + /// Returns true if successful, false if not + public async Task Init(bool overwrite, CancellationToken cancellationToken) + { + if (_isInitialized) + return false; + + _overwrite = overwrite; + + if (!await _xmlDataWriter.Init(cancellationToken)) + return false; + + if (!await _xmlDataReader.Init(cancellationToken)) + return false; + + _isInitialized = true; + + return true; + } + + /// + /// Set the value for the given property + /// + /// The that implements the property + /// The of the property + /// The name of the property + /// The value to set + /// A to await + public async Task SetValue(string propertyName, TProperty value) + { + if (value == null) + return; + + await _cache.SetValue(propertyName, value, _overwrite); + await _xmlDataWriter.Write(propertyName, value.ToString(), _overwrite); + } + + /// + /// Remove the value for the given property + /// + /// The of the property + /// The of the property + /// The name of the property + /// The value to set + /// A to await + public async Task RemoveValue(string propertyName, TProperty value) + { + if (value == null) + return; + + await _cache.TryRemoveValue(propertyName, value); + await _xmlDataWriter.Remove(propertyName, value.ToString()); + } + + /// + /// Get the value for the given property, if multiple values are set the first is returned + /// + /// The that implements the property + /// The of the property + /// The name of the property + /// The value for the given property + public async Task GetValue(string propertyName) + { + IEnumerable enumerable = await GetValues(propertyName); + return enumerable == null ? default : enumerable.FirstOrDefault(); + } + + /// + /// Get all the values that are set for the given property + /// + /// The that implements the property + /// The of the property + /// The name of the property + /// An with all the values for the property + public async Task> GetValues(string propertyName) + { + IEnumerable cachedValues = await _cache.TryGetValues(propertyName); + if (cachedValues != null) + return cachedValues; + + return await _xmlDataReader.Read(propertyName); + } + + /// + /// Dispose used resources asynchronously + /// + /// A to await + public async ValueTask DisposeAsync() + { + await _xmlDataReader.DisposeAsync(); + await _xmlDataWriter.DisposeAsync(); + } + } +} \ No newline at end of file diff --git a/GBase/DataHandling/XmlDataReader.cs b/GBase/DataHandling/XmlDataReader.cs new file mode 100644 index 0000000..979fe01 --- /dev/null +++ b/GBase/DataHandling/XmlDataReader.cs @@ -0,0 +1,104 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Xml.Linq; +using GBase.Interfaces.DataHandling; +using GBase.Interfaces.DataHandling.Xml; + +namespace GBase.DataHandling +{ + /// + /// A that reads from a xml file + /// + public class XmlDataReader : IXmlDataReader + { + private readonly FileStream _file; + private XDocument _xmlDocument; + private XElement _rootElement; + + private bool _isInitialized; + private CancellationToken _cancellationToken; + + /// + /// A that reads from a xml file + /// + /// The path to the xml file + public XmlDataReader(string path) + { + _file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + } + + /// + /// Initialize the + /// + /// A to cancel the async operation + /// Returns true if successful, false if not + public async Task Init(CancellationToken cancellationToken) + { + if (_isInitialized) + return false; + + _cancellationToken = cancellationToken; + _xmlDocument = await XDocument.LoadAsync(_file, LoadOptions.None, _cancellationToken); + + _rootElement = _xmlDocument.Root; + if (_rootElement == null) + throw new Exception("No root element found."); + + _isInitialized = true; + + return true; + } + + /// + /// Read the data of a property + /// + /// The + /// The of the property + /// The name of the property + /// The data of the given property, null if no data found + public async Task> Read(string propertyName) + //TODO: Read currently doesn't work for newly added items -> probably because file was loaded before new items were added; is probably not a problem -> cache + { + string typeName = typeof(T).FullName; + if (typeName == null) + throw new ArgumentNullException(nameof(typeName)); + + return await Task.Run(() => + { + XElement typeElement = _rootElement.Element(typeName); + XElement propertyElement = typeElement?.Element(propertyName); + XAttribute propertyTypeAttribute = propertyElement?.Attribute(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME); + if (propertyTypeAttribute == null) + return null; + + Type propertyType = Type.GetType(propertyTypeAttribute.Value); + if (propertyType != typeof(TProperty)) + throw new InvalidOperationException("Invalid Type found for the read object."); + + List valueElements = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).ToList(); + if (!valueElements.Any()) + return null; + + IEnumerable values = valueElements.Select(v => v.Value); + return values.Select(value => (TProperty)Convert.ChangeType(value, typeof(TProperty))).ToList(); + }, _cancellationToken); + } + + /// + /// Dispose used resources asynchronously + /// + /// A to await + public async ValueTask DisposeAsync() + { + await _file.DisposeAsync(); + } + } +} \ No newline at end of file diff --git a/GBase/DataHandling/XmlDataWriter.cs b/GBase/DataHandling/XmlDataWriter.cs new file mode 100644 index 0000000..f25f13d --- /dev/null +++ b/GBase/DataHandling/XmlDataWriter.cs @@ -0,0 +1,168 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Xml.Linq; +using GBase.Interfaces.DataHandling; +using GBase.Interfaces.DataHandling.Xml; + +namespace GBase.DataHandling +{ + /// + /// A that writes to a xml file + /// + public class XmlDataWriter : IXmlDataWriter + { + private readonly string _rootElementName; + private readonly FileStream _file; + + private XDocument _xmlDocument; + private XElement _rootElement; + + private bool _isInitialized; + private CancellationToken _cancellationToken; + + /// + /// A that writes to an xml file + /// + /// The path to the xml file + /// The root element name of the xml file + public XmlDataWriter(string path, string rootElementName) + { + _rootElementName = rootElementName; + _file = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); + } + + /// + /// Initialize the + /// + /// A to cancel the async operation + /// Returns true if successful, false if not + public async Task Init(CancellationToken cancellationToken) + { + if (_isInitialized) + return false; + + _cancellationToken = cancellationToken; + //if the xml file is empty, write the root element + if (_file.Length <= 3) //<= 3 because of BOM + { + _xmlDocument = new XDocument(); + _xmlDocument.Add(new XElement(_rootElementName)); + _file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it + await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, cancellationToken); + } + else + { + _xmlDocument = await XDocument.LoadAsync(_file, LoadOptions.None, _cancellationToken); + } + + _rootElement = _xmlDocument.Root;//?.Element(_rootElementName); + if (_rootElement == null) + throw new Exception("No root element found."); + + _isInitialized = true; + return true; + } + + /// + /// Write the data of a property + /// + /// The that implements the property + /// The of the property + /// The name of the property + /// The value of the property + /// If true an existing value is overwritten, if false an additional value is added + /// A to await + public async Task Write(string propertyName, string value, bool overwrite) + { + string typeName = typeof(T).FullName; + if (typeName == null) + throw new ArgumentNullException(nameof(typeName)); + + _file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it + + XElement typeElement = _rootElement.Element(typeName); + if (typeElement != null) //type element already exists + { + XElement propertyElement = typeElement.Element(propertyName); + if (propertyElement != null) //property element already exists + { + XElement valueElement = propertyElement.Element(XmlDataHandler.VALUE_ELEMENT_NAME); + if (valueElement != null && overwrite) //value element exists and overwrite is true + { + valueElement.Value = value; //overwrite existing value + } + else if (!overwrite && propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).Any(v => v.Value.Equals(value))) //no overwrite and same value exists already + { + XElement sameValueElement = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).First(v => v.Value.Equals(value)); + sameValueElement.Remove(); //remove the already existing value from its current position + propertyElement.AddFirst(sameValueElement); //add it as the first element again + } + else //no value element exists or overwrite is false + propertyElement.AddFirst(new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //add a new value element + } + else //property element doesn't exist + { + propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element + propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, typeof(TProperty).FullName); //add the property type attribute + + typeElement.Add(propertyElement); //create new property element with the value element + } + } + else //type element doesn't exist + { + XElement propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element + propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, typeof(TProperty).FullName); //add the property type attribute + + _rootElement.Add(new XElement(typeName, propertyElement)); //create a new type element with the new property element + } + + //TODO: check if whole file is overwritten (probably) -> performance issues for large files? + await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, _cancellationToken); //save the document with the added elements + } + + /// + /// Remove the value for the given property + /// + /// The of the property + /// The of the property + /// The name of the property + /// The value to set + /// A to await + public async Task Remove(string propertyName, string value) + { + string typeName = typeof(T).FullName; + if (typeName == null) + throw new ArgumentNullException(nameof(typeName)); + + _file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it + + XElement typeElement = _rootElement.Element(typeName); + XElement propertyElement = typeElement?.Element(propertyName); + XElement valueElement = propertyElement?.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).FirstOrDefault(e => e.Value.Equals(value)); + if (valueElement == null) + return; + + valueElement.Remove(); + + //TODO: check if whole file is overwritten (probably) -> performance issues for large files? + await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, _cancellationToken); //save the document with the added elements + } + + /// + /// Dispose used resources asynchronously + /// + /// A to await + public async ValueTask DisposeAsync() + { + await _xmlDocument.SaveAsync(_file, SaveOptions.None, _cancellationToken); + await _file.DisposeAsync(); + } + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs b/GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs new file mode 100644 index 0000000..e02a452 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs @@ -0,0 +1,46 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace GBase.Interfaces.DataHandling.Cache +{ + /// + /// An interface for the + /// + public interface IDataHandlerCache + { + /// + /// Set the value for the given property + /// + /// The that implements the property + /// The of the property + /// The name of the property + /// The value to set + /// If true an existing value is overwritten, if false an additional value is added + /// A to await + Task SetValue(string propertyName, TProperty value, bool overwrite); + + /// + /// Remove the value for the given property + /// + /// The of the property + /// The of the property + /// The name of the property + /// The value to set + /// A to await + Task TryRemoveValue(string propertyName, TProperty value); + + /// + /// Try to get values from the cache for the given property + /// + /// The that implements the property + /// The of the property + /// The name of the property + /// An with all the values for the property + Task> TryGetValues(string propertyName); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Cache/IDataHandlerCacheEntry.cs b/GBase/Interfaces/DataHandling/Cache/IDataHandlerCacheEntry.cs new file mode 100644 index 0000000..0fe036b --- /dev/null +++ b/GBase/Interfaces/DataHandling/Cache/IDataHandlerCacheEntry.cs @@ -0,0 +1,25 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Collections.Generic; + +namespace GBase.Interfaces.DataHandling.Cache +{ + /// + /// Entry for the + /// + public interface IDataHandlerCacheEntry + { + /// + /// The of the + /// + Type Type { get; } + + /// + /// The properties of the + /// + List Properties { get; } + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Cache/IDataHandlerCachePropertyEntry.cs b/GBase/Interfaces/DataHandling/Cache/IDataHandlerCachePropertyEntry.cs new file mode 100644 index 0000000..40b888f --- /dev/null +++ b/GBase/Interfaces/DataHandling/Cache/IDataHandlerCachePropertyEntry.cs @@ -0,0 +1,29 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System.Collections.Generic; + +namespace GBase.Interfaces.DataHandling.Cache +{ + /// + /// A property entry for the + /// + public interface IDataHandlerCachePropertyEntry + { + /// + /// The name of the property + /// + string PropertyName { get; } + + /// + /// This property is initialized in the + /// + bool IsInitialized { get; set; } + + /// + /// The values of the property + /// + List Values { get; } + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/IDataHandler.cs b/GBase/Interfaces/DataHandling/IDataHandler.cs new file mode 100644 index 0000000..cc600be --- /dev/null +++ b/GBase/Interfaces/DataHandling/IDataHandler.cs @@ -0,0 +1,63 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace GBase.Interfaces.DataHandling +{ + /// + /// Interface for data handlers to implement + /// + public interface IDataHandler : IAsyncDisposable + { + /// + /// Initialize the + /// + /// If true an existing value is overwritten, if false an additional value is added + /// A to cancel the async operation + /// Returns true if successful, false if not + Task Init(bool overwrite, CancellationToken cancellationToken); + + /// + /// Set the value for the given property + /// + /// The of the property + /// The of the property + /// The name of the property + /// The value to set + /// A to await + Task SetValue(string propertyName, TProperty value); + + /// + /// Remove the value for the given property + /// + /// The of the property + /// The of the property + /// The name of the property + /// The value to set + /// A to await + Task RemoveValue(string propertyName, TProperty value); + + /// + /// Get the value for the given property, if multiple values are set the first is returned + /// + /// The of the property + /// The of the property + /// The name of the property + /// The value for the given property + Task GetValue(string propertyName); + + /// + /// Get all the values that are set for the given property + /// + /// The of the property + /// The of the property + /// The name of the property + /// An with all the values for the property + Task> GetValues(string propertyName); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/IDataReader.cs b/GBase/Interfaces/DataHandling/IDataReader.cs new file mode 100644 index 0000000..e6d34da --- /dev/null +++ b/GBase/Interfaces/DataHandling/IDataReader.cs @@ -0,0 +1,33 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace GBase.Interfaces.DataHandling +{ + /// + /// Interface for data readers to implement + /// + public interface IDataReader : IAsyncDisposable + { + /// + /// Initialize the + /// + /// A to cancel the async operation + /// Returns true if successful, false if not + Task Init(CancellationToken cancellationToken); + + /// + /// Read the data of a property + /// + /// The + /// The of the property + /// The name of the property + /// The data of the given property, null if no data found + Task> Read(string propertyName); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/IDataWriter.cs b/GBase/Interfaces/DataHandling/IDataWriter.cs new file mode 100644 index 0000000..c049b66 --- /dev/null +++ b/GBase/Interfaces/DataHandling/IDataWriter.cs @@ -0,0 +1,44 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace GBase.Interfaces.DataHandling +{ + /// + /// Interface for data writers to implement + /// + public interface IDataWriter : IAsyncDisposable + { + /// + /// Initialize the + /// + /// A to cancel the async operation + /// Returns true if successful, false if not + Task Init(CancellationToken cancellationToken); + + /// + /// Write the data of a property + /// + /// The + /// The of the property + /// The name of the property + /// The value of the property + /// If true an existing value is overwritten, if false an additional value is added + /// A to await + Task Write(string propertyName, string value, bool overwrite); + + /// + /// Remove the value for the given property + /// + /// The of the property + /// The of the property + /// The name of the property + /// The value to set + /// A to await + Task Remove(string propertyName, string value); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheEntryFactory.cs b/GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheEntryFactory.cs new file mode 100644 index 0000000..fce263e --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheEntryFactory.cs @@ -0,0 +1,13 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; + +namespace GBase.Interfaces.DataHandling.Xml.Cache.Factories +{ + public interface IXmlDataHandlerCacheEntryFactory + { + IXmlDataHandlerCacheEntry Create(Type type, string propertyName, object value); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheFactory.cs b/GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheFactory.cs new file mode 100644 index 0000000..ffb517f --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheFactory.cs @@ -0,0 +1,11 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +namespace GBase.Interfaces.DataHandling.Xml.Cache.Factories +{ + public interface IXmlDataHandlerCacheFactory + { + IXmlDataHandlerCache Create(IXmlDataReader xmlDataReader); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCachePropertyEntryFactory.cs b/GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCachePropertyEntryFactory.cs new file mode 100644 index 0000000..23ef25c --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCachePropertyEntryFactory.cs @@ -0,0 +1,11 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +namespace GBase.Interfaces.DataHandling.Xml.Cache.Factories +{ + public interface IXmlDataHandlerCachePropertyEntryFactory + { + IXmlDataHandlerCachePropertyEntry Create(string propertyName, object value); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCache.cs b/GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCache.cs new file mode 100644 index 0000000..cbd5c23 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCache.cs @@ -0,0 +1,16 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Interfaces.DataHandling.Cache; + +namespace GBase.Interfaces.DataHandling.Xml.Cache +{ + /// + /// An interface for the + /// + public interface IXmlDataHandlerCache : IDataHandlerCache + { + + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCacheEntry.cs b/GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCacheEntry.cs new file mode 100644 index 0000000..cc2506c --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCacheEntry.cs @@ -0,0 +1,16 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Interfaces.DataHandling.Cache; + +namespace GBase.Interfaces.DataHandling.Xml.Cache +{ + /// + /// Entry for the + /// + public interface IXmlDataHandlerCacheEntry : IDataHandlerCacheEntry + { + + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCachePropertyEntry.cs b/GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCachePropertyEntry.cs new file mode 100644 index 0000000..ba7ec22 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCachePropertyEntry.cs @@ -0,0 +1,16 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Interfaces.DataHandling.Cache; + +namespace GBase.Interfaces.DataHandling.Xml.Cache +{ + /// + /// A property entry for the + /// + public interface IXmlDataHandlerCachePropertyEntry : IDataHandlerCachePropertyEntry + { + + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataHandlerFactory.cs b/GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataHandlerFactory.cs new file mode 100644 index 0000000..52b5f53 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataHandlerFactory.cs @@ -0,0 +1,11 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +namespace GBase.Interfaces.DataHandling.Xml.Factories +{ + public interface IXmlDataHandlerFactory + { + IXmlDataHandler Create(); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataReaderFactory.cs b/GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataReaderFactory.cs new file mode 100644 index 0000000..e573acd --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataReaderFactory.cs @@ -0,0 +1,11 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +namespace GBase.Interfaces.DataHandling.Xml.Factories +{ + public interface IXmlDataReaderFactory + { + IXmlDataReader Create(string path); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataWriterFactory.cs b/GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataWriterFactory.cs new file mode 100644 index 0000000..9c2db97 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataWriterFactory.cs @@ -0,0 +1,11 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +namespace GBase.Interfaces.DataHandling.Xml.Factories +{ + public interface IXmlDataWriterFactory + { + IXmlDataWriter Create(string path, string rootElementName); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/IXmlDataHandler.cs b/GBase/Interfaces/DataHandling/Xml/IXmlDataHandler.cs new file mode 100644 index 0000000..acc4845 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/IXmlDataHandler.cs @@ -0,0 +1,14 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +namespace GBase.Interfaces.DataHandling.Xml +{ + /// + /// A that handles its data in an xml file + /// + public interface IXmlDataHandler : IDataHandler + { + + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/IXmlDataReader.cs b/GBase/Interfaces/DataHandling/Xml/IXmlDataReader.cs new file mode 100644 index 0000000..09122ef --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/IXmlDataReader.cs @@ -0,0 +1,14 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +namespace GBase.Interfaces.DataHandling.Xml +{ + /// + /// A that writes to an xml file + /// + public interface IXmlDataReader : IDataReader + { + + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Xml/IXmlDataWriter.cs b/GBase/Interfaces/DataHandling/Xml/IXmlDataWriter.cs new file mode 100644 index 0000000..33a91b6 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Xml/IXmlDataWriter.cs @@ -0,0 +1,14 @@ +// Author: Gockner, Simon +// Created: 2020-02-12 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +namespace GBase.Interfaces.DataHandling.Xml +{ + /// + /// An that writes to a xml file + /// + public interface IXmlDataWriter : IDataWriter + { + + } +} \ No newline at end of file