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 typeStorages = new Dictionary(); public StorageAdapter(OODB oodb,DirectoryInfo baseDirectory) { OODB = oodb; BaseDirectory = baseDirectory; if (!BaseDirectory.Exists) BaseDirectory.Create(); } public void Close() { foreach (KeyValuePair 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> 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 indeces = new HashSet(); public Dictionary searchIndeces = new Dictionary(); 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 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> List() { KeyValuePair create(FileInfo fileInfo) { Guid persistenceID = Guid.Parse(fileInfo.Name.Substring(0, fileInfo.Name.Length - fileInfo.Extension.Length)); return new KeyValuePair(persistenceID,GetDiscriminator(persistenceID)); } return Directory.GetFiles("*.discriminator").Select(create); } public Type GetDiscriminator(Guid persistenceID) { String typeName = ReadDiscriminator(persistenceID); return StorageAdapter.OODB.LookupType(typeName); } } } }