272 lines
9.7 KiB
C#
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);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
}
|