sharp-oodb/StorageAdapter.cs

272 lines
9.7 KiB
C#

using System;
using oodb.descriptor;
using System.Collections.Generic;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Text;
using System.Xml;
using oodb.mapping;
using sharp.logging;
using System.Linq;
using oodb.index;
namespace oodb
{
public class StorageAdapter
{
public OODB OODB { get; }
public DirectoryInfo BaseDirectory { get; }
Dictionary<Type, TypeStorage> typeStorages = new Dictionary<Type, TypeStorage>();
public StorageAdapter(OODB oodb,DirectoryInfo baseDirectory)
{
OODB = oodb;
BaseDirectory = baseDirectory;
if (!BaseDirectory.Exists)
BaseDirectory.Create();
}
public void Close()
{
foreach (KeyValuePair<Type,TypeStorage> kvp in typeStorages)
{
foreach (Index index in kvp.Value.indeces)
index.Save();
}
}
public void Save(Persistent persistent)
{
GetTypeStorage(persistent.GetType()).Save(persistent);
}
public void Restore(Persistent persistent)
{
GetTypeStorage(persistent.GetType()).Restore(persistent);
}
public bool Knows(Type type,Guid persistenceID)
{
return GetTypeStorage(type).Knows(persistenceID);
}
public void Reference(Persistent persistent, FieldInfo referencing)
{
GetTypeStorage(persistent.GetType()).Reference(persistent, referencing);
}
public void UnReference(Persistent persistent, FieldInfo referencing)
{
GetTypeStorage(persistent.GetType()).UnReference(persistent, referencing);
}
public IEnumerable<KeyValuePair<Guid,Type>> List(Descriptor descriptor)
{
return GetTypeStorage(descriptor.NativeType).List();
}
public Type GetDiscriminator(Type type,Guid persistenceID)
{
return GetTypeStorage(type).GetDiscriminator(persistenceID);
}
public SearchIndex GetSearchIndex(FieldInfo fieldInfo)
{
return GetTypeStorage(fieldInfo.DeclaringType).GetSearchIndex(fieldInfo);
}
public bool HasSearchIndex(FieldInfo fieldInfo)
{
return GetTypeStorage(fieldInfo.DeclaringType).HasSearchIndex(fieldInfo);
}
public TypeStorage GetTypeStorage(Type type)
{
if (!typeStorages.ContainsKey(type))
{
typeStorages[type] = new TypeStorage(this, type);
}
return typeStorages[type];
}
public class TypeStorage
{
public StorageAdapter StorageAdapter { get; }
public Type PersistentType { get; }
public DirectoryInfo Directory { get; }
public Descriptor Descriptor { get; }
public TypeStorage BaseStorage { get; }
public HashSet<Index> indeces = new HashSet<Index>();
public Dictionary<FieldInfo, SearchIndex> searchIndeces = new Dictionary<FieldInfo, SearchIndex>();
public TypeStorage(StorageAdapter storageAdapter, Type type)
{
StorageAdapter = storageAdapter;
PersistentType = type;
Directory = new DirectoryInfo(Path.Combine(StorageAdapter.BaseDirectory.FullName, type.FullName));
if (!Directory.Exists)
Directory.Create();
Descriptor = storageAdapter.OODB.GetDescriptor(type);
if (Descriptor.BaseDescriptor != null)
{
BaseStorage = StorageAdapter.GetTypeStorage(Descriptor.BaseDescriptor.NativeType);
}
}
public bool AddIndex(Index index)
{
return indeces.Add(index);
}
public bool HasSearchIndex(FieldInfo fieldInfo) => searchIndeces.ContainsKey(fieldInfo);
public SearchIndex GetSearchIndex(FieldInfo fieldInfo)
{
if (!searchIndeces.ContainsKey(fieldInfo))
{
SearchIndex searchIndex = new SearchIndex(StorageAdapter.OODB, fieldInfo);
searchIndeces.Add(fieldInfo, searchIndex);
}
return searchIndeces[fieldInfo];
}
private void RemoveDiscriminator(Guid persistenceID)
{
foreach (Index index in indeces)
{
index.Remove(persistenceID);
}
File.Delete(Path.Combine(Directory.FullName, String.Format("{0}.discriminator", persistenceID.ToString())));
if (BaseStorage != null)
BaseStorage.RemoveDiscriminator(persistenceID);
}
private String ReadDiscriminator(Guid persistenceID)
{
byte[] discriminator = File.ReadAllBytes(Path.Combine(Directory.FullName, String.Format("{0}.discriminator", persistenceID.ToString())));
return Encoding.UTF8.GetString(discriminator);
}
private void WriteDiscriminator(Persistent persistent)
{
foreach (Index index in indeces)
{
index.Add(persistent);
}
using (FileStream fileStream = new FileStream(Path.Combine(Directory.FullName,String.Format("{0}.discriminator",persistent.PersistenceID.ToString())),FileMode.Create))
{
byte[] discriminator = Encoding.UTF8.GetBytes(persistent.GetType().FullName);
fileStream.Write(discriminator, 0, discriminator.Length);
fileStream.Close();
}
if (BaseStorage != null)
BaseStorage.WriteDiscriminator(persistent);
}
public bool Knows(Guid persistenceID)
{
return File.Exists(Path.Combine(Directory.FullName, String.Format("{0}.discriminator", persistenceID.ToString())));
}
public void Save(Persistent persistent)
{
try {
WriteDiscriminator(persistent);
} catch (Exception e)
{
Logger.Default.Log(e);
RemoveDiscriminator(persistent.PersistenceID);
throw e;
}
try
{
Descriptor descriptor = StorageAdapter.OODB.GetDescriptor(persistent.GetType());
XmlDocument xmlDocument = new XmlDocument();
XmlElement persistetInstance = xmlDocument.CreateElement("PersistetInstance");
xmlDocument.AppendChild(persistetInstance);
foreach (KeyValuePair<FieldInfo, FlatTypeMapping> flatField in descriptor.FlatMappings)
{
XmlElement fieldElement = xmlDocument.CreateElement("Field");
fieldElement.SetAttribute("Name", flatField.Key.Name);
fieldElement.AppendChild(flatField.Value.ToXml(xmlDocument, flatField.Key.GetValue(persistent)));
persistetInstance.AppendChild(fieldElement);
}
xmlDocument.Save(Path.Combine(Directory.FullName, String.Format("{0}.xml", persistent.PersistenceID.ToString())));
} catch (Exception e)
{
Logger.Default.Log(LogLevel.ERROR, "StorageAdapter.Save(): {0}", e);
}
}
public void Restore(Persistent persistent)
{
Descriptor descriptor = StorageAdapter.OODB.GetDescriptor(persistent.GetType());
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(Path.Combine(Directory.FullName, String.Format("{0}.xml", persistent.PersistenceID.ToString())));
foreach (XmlElement fieldElement in xmlDocument.SelectNodes("PersistetInstance/Field"))
{
try {
FieldInfo fieldInfo = Descriptor.GetFieldInfo(fieldElement.GetAttribute("Name"));
FlatTypeMapping flatTypeMapping = Descriptor.GetFlatTypeMapping(fieldInfo);
fieldInfo.SetValue(persistent, flatTypeMapping.FromXml(fieldElement.SelectSingleNode("Value") as XmlElement));
} catch (KeyNotFoundException)
{
Logger.Default.Log(LogLevel.WARNING, "data for unknown field {0} ignored", fieldElement.GetAttribute("Name"));
}
}
}
public void Reference(Persistent persistent, FieldInfo referencing)
{
throw new NotSupportedException();
}
public void UnReference(Persistent persistent, FieldInfo referencing)
{
throw new NotSupportedException();
}
public IEnumerable<KeyValuePair<Guid,Type>> List()
{
KeyValuePair<Guid,Type> create(FileInfo fileInfo)
{
Guid persistenceID = Guid.Parse(fileInfo.Name.Substring(0, fileInfo.Name.Length - fileInfo.Extension.Length));
return new KeyValuePair<Guid, Type>(persistenceID,GetDiscriminator(persistenceID));
}
return Directory.GetFiles("*.discriminator").Select(create);
}
public Type GetDiscriminator(Guid persistenceID)
{
String typeName = ReadDiscriminator(persistenceID);
return StorageAdapter.OODB.LookupType(typeName);
}
}
}
}