#10: add dataHandling

pull/26/head
Simon Gockner 6 years ago
parent 648045e5b4
commit 4c6775b48d
  1. 132
      GBase/DataHandling/Cache/XmlDataHandlerCache.cs
  2. 41
      GBase/DataHandling/Cache/XmlDataHandlerCacheEntry.cs
  3. 41
      GBase/DataHandling/Cache/XmlDataHandlerCachePropertyEntry.cs
  4. 160
      GBase/DataHandling/XmlDataHandler.cs
  5. 104
      GBase/DataHandling/XmlDataReader.cs
  6. 168
      GBase/DataHandling/XmlDataWriter.cs
  7. 46
      GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs
  8. 25
      GBase/Interfaces/DataHandling/Cache/IDataHandlerCacheEntry.cs
  9. 29
      GBase/Interfaces/DataHandling/Cache/IDataHandlerCachePropertyEntry.cs
  10. 63
      GBase/Interfaces/DataHandling/IDataHandler.cs
  11. 33
      GBase/Interfaces/DataHandling/IDataReader.cs
  12. 44
      GBase/Interfaces/DataHandling/IDataWriter.cs
  13. 13
      GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheEntryFactory.cs
  14. 11
      GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCacheFactory.cs
  15. 11
      GBase/Interfaces/DataHandling/Xml/Cache/Factories/IXmlDataHandlerCachePropertyEntryFactory.cs
  16. 16
      GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCache.cs
  17. 16
      GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCacheEntry.cs
  18. 16
      GBase/Interfaces/DataHandling/Xml/Cache/IXmlDataHandlerCachePropertyEntry.cs
  19. 11
      GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataHandlerFactory.cs
  20. 11
      GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataReaderFactory.cs
  21. 11
      GBase/Interfaces/DataHandling/Xml/Factories/IXmlDataWriterFactory.cs
  22. 14
      GBase/Interfaces/DataHandling/Xml/IXmlDataHandler.cs
  23. 14
      GBase/Interfaces/DataHandling/Xml/IXmlDataReader.cs
  24. 14
      GBase/Interfaces/DataHandling/Xml/IXmlDataWriter.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
{
/// <summary>
/// An interface for the <see cref="IXmlDataHandlerCache"/>
/// </summary>
public class XmlDataHandlerCache : IXmlDataHandlerCache
{
private readonly IXmlDataReader _xmlDataReader;
private readonly IXmlDataHandlerCacheEntryFactory _xmlDataHandlerCacheEntryFactory;
private readonly IXmlDataHandlerCachePropertyEntryFactory _xmlDataHandlerCachePropertyEntryFactory;
private readonly List<IXmlDataHandlerCacheEntry> _cache;
/// <summary>
/// An interface for the <see cref="IXmlDataHandlerCache"/>
/// </summary>
/// <param name="xmlDataReader">The <see cref="IXmlDataReader"/></param>
/// <param name="xmlDataHandlerCacheEntryFactory">A factory for the <see cref="IXmlDataHandlerCacheEntry"/></param>
/// <param name="xmlDataHandlerCachePropertyEntryFactory">A factory for the <see cref="IXmlDataHandlerCachePropertyEntry"/></param>
public XmlDataHandlerCache(IXmlDataReader xmlDataReader,
IXmlDataHandlerCacheEntryFactory xmlDataHandlerCacheEntryFactory,
IXmlDataHandlerCachePropertyEntryFactory xmlDataHandlerCachePropertyEntryFactory)
{
_xmlDataReader = xmlDataReader;
_xmlDataHandlerCacheEntryFactory = xmlDataHandlerCacheEntryFactory;
_xmlDataHandlerCachePropertyEntryFactory = xmlDataHandlerCachePropertyEntryFactory;
_cache = new List<IXmlDataHandlerCacheEntry>();
}
/// <summary>
/// Set the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task SetValue<T, TProperty>(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
}
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task TryRemoveValue<T, TProperty>(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);
}
/// <summary>
/// Try to get values from the cache for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
public async Task<IEnumerable<TProperty>> TryGetValues<T, TProperty>(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<TProperty> values = (await _xmlDataReader.Read<T, TProperty>(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<TProperty>();
}
}
}

@ -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
{
/// <summary>
/// Entry for the <see cref="IDataHandlerCache"/>
/// </summary>
public class XmlDataHandlerCacheEntry : IXmlDataHandlerCacheEntry
{
/// <summary>
/// Entry for the <see cref="IDataHandlerCache"/>
/// </summary>
/// <param name="type">The <see cref="Type"/> that implements the property</param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value of the property</param>
/// <param name="xmlDataHandlerCachePropertyEntryFactory">Factory for the <see cref="IXmlDataHandlerCachePropertyEntry"/></param>
public XmlDataHandlerCacheEntry(Type type, string propertyName, object value, IXmlDataHandlerCachePropertyEntryFactory xmlDataHandlerCachePropertyEntryFactory)
{
Type = type;
Properties = new List<IDataHandlerCachePropertyEntry>() { xmlDataHandlerCachePropertyEntryFactory.Create(propertyName, value) };
}
/// <summary>
/// The <see cref="Type"/> of the <see cref="IXmlDataHandlerCacheEntry"/>
/// </summary>
public Type Type { get; }
/// <summary>
/// The properties of the <see cref="IXmlDataHandlerCacheEntry"/>
/// </summary>
public List<IDataHandlerCachePropertyEntry> Properties { get; }
}
}

@ -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
{
/// <summary>
/// A property entry for the <see cref="IXmlDataHandlerCacheEntry"/>
/// </summary>
public class XmlDataHandlerCachePropertyEntry : IXmlDataHandlerCachePropertyEntry
{
/// <summary>
/// A property entry for the <see cref="IXmlDataHandlerCacheEntry"/>
/// </summary>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value of the property</param>
public XmlDataHandlerCachePropertyEntry(string propertyName, object value)
{
PropertyName = propertyName;
Values = new List<object>() { value };
}
/// <summary>
/// The name of the property
/// </summary>
public string PropertyName { get; }
/// <summary>
/// This property is initialized in the <see cref="IXmlDataHandlerCache"/>
/// </summary>
public bool IsInitialized { get; set; }
/// <summary>
/// The values of the property
/// </summary>
public List<object> Values { get; }
}
}

@ -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?
/// <summary>
/// A <see cref="IDataHandler"/> that handles its data in an xml file
/// </summary>
public class XmlDataHandler : IXmlDataHandler
{
/// <summary>
/// The element name of the value element
/// </summary>
public const string VALUE_ELEMENT_NAME = "Value";
/// <summary>
/// The attribute name of the value <see cref="Type"/> attribute
/// </summary>
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;
/// <summary>
/// A <see cref="IDataHandler"/> that handles its data in an xml file
/// </summary>
/// <param name="path">The path to the xml file</param>
/// <param name="rootElementName">The root element name of the xml file</param>
/// <param name="xmlDataReaderFactory">The <see cref="IXmlDataReader"/> factory</param>
/// <param name="xmlDataWriterFactory">The <see cref="IXmlDataWriter"/> factory</param>
/// <param name="xmlDataHandlerCacheFactory">The <see cref="IXmlDataHandlerCache"/> factory</param>
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);
}
/// <summary>
/// Initialize the <see cref="XmlDataHandler"/>
/// </summary>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
public async Task<bool> 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;
}
/// <summary>
/// Set the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task SetValue<T, TProperty>(string propertyName, TProperty value)
{
if (value == null)
return;
await _cache.SetValue<T, TProperty>(propertyName, value, _overwrite);
await _xmlDataWriter.Write<T, TProperty>(propertyName, value.ToString(), _overwrite);
}
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task RemoveValue<T, TProperty>(string propertyName, TProperty value)
{
if (value == null)
return;
await _cache.TryRemoveValue<T, TProperty>(propertyName, value);
await _xmlDataWriter.Remove<T, TProperty>(propertyName, value.ToString());
}
/// <summary>
/// Get the value for the given property, if multiple values are set the first is returned
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>The value for the given property</returns>
public async Task<TProperty> GetValue<T, TProperty>(string propertyName)
{
IEnumerable<TProperty> enumerable = await GetValues<T, TProperty>(propertyName);
return enumerable == null ? default : enumerable.FirstOrDefault();
}
/// <summary>
/// Get all the values that are set for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
public async Task<IEnumerable<TProperty>> GetValues<T, TProperty>(string propertyName)
{
IEnumerable<TProperty> cachedValues = await _cache.TryGetValues<T, TProperty>(propertyName);
if (cachedValues != null)
return cachedValues;
return await _xmlDataReader.Read<T, TProperty>(propertyName);
}
/// <summary>
/// Dispose used resources asynchronously
/// </summary>
/// <returns>A <see cref="ValueTask"/> to await</returns>
public async ValueTask DisposeAsync()
{
await _xmlDataReader.DisposeAsync();
await _xmlDataWriter.DisposeAsync();
}
}
}

@ -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
{
/// <summary>
/// A <see cref="IDataReader"/> that reads from a xml file
/// </summary>
public class XmlDataReader : IXmlDataReader
{
private readonly FileStream _file;
private XDocument _xmlDocument;
private XElement _rootElement;
private bool _isInitialized;
private CancellationToken _cancellationToken;
/// <summary>
/// A <see cref="IDataReader"/> that reads from a xml file
/// </summary>
/// <param name="path">The path to the xml file</param>
public XmlDataReader(string path)
{
_file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
/// <summary>
/// Initialize the <see cref="XmlDataReader"/>
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
public async Task<bool> 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;
}
/// <summary>
/// Read the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>The data of the given property, null if no data found</returns>
public async Task<IEnumerable<TProperty>> Read<T, TProperty>(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<XElement> valueElements = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).ToList();
if (!valueElements.Any())
return null;
IEnumerable<string> values = valueElements.Select(v => v.Value);
return values.Select(value => (TProperty)Convert.ChangeType(value, typeof(TProperty))).ToList();
}, _cancellationToken);
}
/// <summary>
/// Dispose used resources asynchronously
/// </summary>
/// <returns>A <see cref="ValueTask"/> to await</returns>
public async ValueTask DisposeAsync()
{
await _file.DisposeAsync();
}
}
}

@ -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
{
/// <summary>
/// A <see cref="IDataWriter"/> that writes to a xml file
/// </summary>
public class XmlDataWriter : IXmlDataWriter
{
private readonly string _rootElementName;
private readonly FileStream _file;
private XDocument _xmlDocument;
private XElement _rootElement;
private bool _isInitialized;
private CancellationToken _cancellationToken;
/// <summary>
/// A <see cref="IDataWriter"/> that writes to an xml file
/// </summary>
/// <param name="path">The path to the xml file</param>
/// <param name="rootElementName">The root element name of the xml file</param>
public XmlDataWriter(string path, string rootElementName)
{
_rootElementName = rootElementName;
_file = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
}
/// <summary>
/// Initialize the <see cref="XmlDataWriter"/>
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
public async Task<bool> 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;
}
/// <summary>
/// Write the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value of the property</param>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task Write<T, TProperty>(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
}
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task Remove<T, TProperty>(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
}
/// <summary>
/// Dispose used resources asynchronously
/// </summary>
/// <returns>A <see cref="ValueTask"/> to await</returns>
public async ValueTask DisposeAsync()
{
await _xmlDocument.SaveAsync(_file, SaveOptions.None, _cancellationToken);
await _file.DisposeAsync();
}
}
}

@ -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
{
/// <summary>
/// An interface for the <see cref="IDataHandlerCache"/>
/// </summary>
public interface IDataHandlerCache
{
/// <summary>
/// Set the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <returns>A <see cref="Task"/> to await</returns>
Task SetValue<T, TProperty>(string propertyName, TProperty value, bool overwrite);
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
Task TryRemoveValue<T, TProperty>(string propertyName, TProperty value);
/// <summary>
/// Try to get values from the cache for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
Task<IEnumerable<TProperty>> TryGetValues<T, TProperty>(string propertyName);
}
}

@ -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
{
/// <summary>
/// Entry for the <see cref="IDataHandlerCache"/>
/// </summary>
public interface IDataHandlerCacheEntry
{
/// <summary>
/// The <see cref="Type"/> of the <see cref="IDataHandlerCacheEntry"/>
/// </summary>
Type Type { get; }
/// <summary>
/// The properties of the <see cref="IDataHandlerCacheEntry"/>
/// </summary>
List<IDataHandlerCachePropertyEntry> Properties { get; }
}
}

@ -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
{
/// <summary>
/// A property entry for the <see cref="IDataHandlerCacheEntry"/>
/// </summary>
public interface IDataHandlerCachePropertyEntry
{
/// <summary>
/// The name of the property
/// </summary>
string PropertyName { get; }
/// <summary>
/// This property is initialized in the <see cref="IDataHandlerCache"/>
/// </summary>
bool IsInitialized { get; set; }
/// <summary>
/// The values of the property
/// </summary>
List<object> Values { get; }
}
}

@ -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
{
/// <summary>
/// Interface for data handlers to implement
/// </summary>
public interface IDataHandler : IAsyncDisposable
{
/// <summary>
/// Initialize the <see cref="IDataHandler"/>
/// </summary>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
Task<bool> Init(bool overwrite, CancellationToken cancellationToken);
/// <summary>
/// Set the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
Task SetValue<T, TProperty>(string propertyName, TProperty value);
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
Task RemoveValue<T, TProperty>(string propertyName, TProperty value);
/// <summary>
/// Get the value for the given property, if multiple values are set the first is returned
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>The value for the given property</returns>
Task<TProperty> GetValue<T, TProperty>(string propertyName);
/// <summary>
/// Get all the values that are set for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
Task<IEnumerable<TProperty>> GetValues<T, TProperty>(string propertyName);
}
}

@ -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
{
/// <summary>
/// Interface for data readers to implement
/// </summary>
public interface IDataReader : IAsyncDisposable
{
/// <summary>
/// Initialize the <see cref="IDataReader"/>
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
Task<bool> Init(CancellationToken cancellationToken);
/// <summary>
/// Read the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>The data of the given property, null if no data found</returns>
Task<IEnumerable<TProperty>> Read<T, TProperty>(string propertyName);
}
}

@ -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
{
/// <summary>
/// Interface for data writers to implement
/// </summary>
public interface IDataWriter : IAsyncDisposable
{
/// <summary>
/// Initialize the <see cref="IDataWriter"/>
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
Task<bool> Init(CancellationToken cancellationToken);
/// <summary>
/// Write the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value of the property</param>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <returns>A <see cref="Task"/> to await</returns>
Task Write<T, TProperty>(string propertyName, string value, bool overwrite);
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
Task Remove<T, TProperty>(string propertyName, string value);
}
}

@ -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);
}
}

@ -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);
}
}

@ -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);
}
}

@ -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
{
/// <summary>
/// An interface for the <see cref="IXmlDataHandlerCache"/>
/// </summary>
public interface IXmlDataHandlerCache : IDataHandlerCache
{
}
}

@ -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
{
/// <summary>
/// Entry for the <see cref="IXmlDataHandlerCache"/>
/// </summary>
public interface IXmlDataHandlerCacheEntry : IDataHandlerCacheEntry
{
}
}

@ -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
{
/// <summary>
/// A property entry for the <see cref="IXmlDataHandlerCacheEntry"/>
/// </summary>
public interface IXmlDataHandlerCachePropertyEntry : IDataHandlerCachePropertyEntry
{
}
}

@ -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();
}
}

@ -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);
}
}

@ -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);
}
}

@ -0,0 +1,14 @@
// Author: Gockner, Simon
// Created: 2020-02-12
// Copyright(c) 2020 SimonG. All Rights Reserved.
namespace GBase.Interfaces.DataHandling.Xml
{
/// <summary>
/// A <see cref="IDataHandler"/> that handles its data in an xml file
/// </summary>
public interface IXmlDataHandler : IDataHandler
{
}
}

@ -0,0 +1,14 @@
// Author: Gockner, Simon
// Created: 2020-02-12
// Copyright(c) 2020 SimonG. All Rights Reserved.
namespace GBase.Interfaces.DataHandling.Xml
{
/// <summary>
/// A <see cref="IDataReader"/> that writes to an xml file
/// </summary>
public interface IXmlDataReader : IDataReader
{
}
}

@ -0,0 +1,14 @@
// Author: Gockner, Simon
// Created: 2020-02-12
// Copyright(c) 2020 SimonG. All Rights Reserved.
namespace GBase.Interfaces.DataHandling.Xml
{
/// <summary>
/// An <see cref="IDataWriter"/> that writes to a xml file
/// </summary>
public interface IXmlDataWriter : IDataWriter
{
}
}
Loading…
Cancel
Save