// /** // * File: ODB.cs // * Author: haraldwolff // * // * This file and it's content is copyrighted by the Author and / or copyright holder. // * Any use wihtout proper permission is illegal and may lead to legal actions. // * // * // **/ using System; using System.IO; using System.Collections.Generic; using Castle.DynamicProxy; using ln.types.serialize; using Castle.Components.DictionaryAdapter; using System.Linq; namespace ln.types.odb { public class ODB : ODB { public T Root { get => (T)RootObject; } public ODB(String basePath) :base(basePath, typeof(T)) { } } public partial class ODB { public object RootObject { get; protected set; } public String BasePath { get; set; } private ProxyGenerator proxyGenerator = new ProxyGenerator(); private Dictionary> persistentObjects = new Dictionary>(); private Dictionary persistentProxies = new Dictionary(); private Type RootType; public ODB(string basePath) { BasePath = Path.GetFullPath(basePath); if (!Directory.Exists(BasePath)) { Directory.CreateDirectory(BasePath); } } public ODB(String basePath, Type rootType) : this(basePath) { RootType = rootType; Initialize(); } public ODB(String basePath,object rootObject) : this(basePath) { RootType = rootObject.GetType(); RootObject = rootObject; Initialize(); } private void Initialize() { if (RootObject == null) { string rootHint = Path.Combine(BasePath, "root.hint"); if (File.Exists(rootHint)) { using (ObjectReader objectReader = new ObjectReader(rootHint)) { Guid persistenceID = objectReader.Read(); RootObject = GetPersistent(persistenceID); } } else { RootObject = Activator.CreateInstance(RootType); } } } public bool Contains(Guid persistenceID) { string fn = Path.Combine(GetPersistentPath(persistenceID), String.Format("{0}.0",persistenceID)); return File.Exists(fn); } IPersistent LoadPersistent(Guid guid) { IPersistent o = GetCachedPersistent(guid); if (o == null) { throw new NotImplementedException(); } return o; } public void SavePersistent(IPersistent o) => SavePersistent(o, true); public void SavePersistent(IPersistent o,bool recurse) { SaveCollector saveCollector = new SaveCollector(this); saveCollector.AddPersistent(o, recurse); foreach (Guid persistenceID in saveCollector.GetCollectedPersistenceIDs()) { SaveBytes(persistenceID, saveCollector.GetPersistentBytes(persistenceID)); } } /* File I/O */ private string GetPersistentPath(Guid persistenceID) { byte[] idBytes = persistenceID.ToByteArray(); return Path.Combine(BasePath, BitConverter.ToString(idBytes, 0, 4)); } private void SaveBytes(Guid persistenceID,byte[] bytes) { String p = GetPersistentPath(persistenceID); String fnbase = Path.Combine(p, persistenceID.ToString()); if (!Directory.Exists(p)) Directory.CreateDirectory(p); String fnn = String.Format("{0}.new", fnbase); using (FileStream fs = new FileStream(fnn, FileMode.CreateNew)) { fs.Write(bytes,0,bytes.Length); fs.Close(); } for (int n=5;n>0;n--) { string fn1 = String.Format("{0}.{1}",fnbase,n-1); string fn2 = String.Format("{0}.{1}", fnbase, n); if (File.Exists(fn1)) File.Move(fn1, fn2); } string fn = String.Format("{0}.{1}", fnbase, 0); File.Move(fnn, fn); } private IPersistent GetCachedPersistent(Guid persistenceID) { lock (this) { if (persistentObjects.ContainsKey(persistenceID)) { WeakReference weak = persistentObjects[persistenceID]; IPersistent persistent = null; if (weak.TryGetTarget(out persistent)) { return persistent; } else { persistentObjects.Remove(persistenceID); } } } return null; } /** * GetPersistent(..): Return Instance of an IPersistent (may be a proxy) * **/ public IPersistent GetPersistent(Guid persistenceID) { if (Guid.Empty.Equals(persistenceID)) return null; if (persistentObjects.ContainsKey(persistenceID)) { IPersistent o = GetCachedPersistent(persistenceID); if (o == null) { o = LoadPersistent(persistenceID); } return o; } return null; } class SaveCollector { public ODB ODB { get; } public Guid[] GetCollectedPersistenceIDs() { return persistentBytes.Keys.ToArray(); } public byte[] GetPersistentBytes(Guid persistenceID) { return persistentBytes[persistenceID]; } private Dictionary persistentBytes = new Dictionary(); public SaveCollector(ODB odb) { ODB = odb; } public void AddPersistent(IPersistent persistent,bool recurse) { MemoryStream objectStream = new MemoryStream(); ODBObjectWriter objectWriter = new ODBObjectWriter(ODB, objectStream); objectWriter.Write(persistent); persistentBytes.Add(persistent.GetPersistenceID(), objectStream.ToArray()); if (recurse) { foreach (IPersistent referencedPersistent in objectWriter.ReferencedPersistents) { AddPersistent(referencedPersistent,recurse); } } else { foreach (IPersistent referencedPersistent in objectWriter.ReferencedPersistents) { if (!ODB.Contains(referencedPersistent.GetPersistenceID())) { AddPersistent(referencedPersistent, recurse); } } } } } class LazyInterceptor : IInterceptor { ODB odb; WeakReference target = null; public LazyInterceptor(ODB odb, Guid persistentID) { this.odb = odb; } public void Intercept(IInvocation invocation) { object t = target; throw new NotImplementedException(); } } } }