ln.types/odb/ODB.cs
Harald Wolff 26276074cc WIP
2019-03-21 07:43:39 +01:00

278 lines
7.8 KiB
C#

// /**
// * 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<T> : 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<Guid, WeakReference<IPersistent>> persistentObjects = new Dictionary<Guid, WeakReference<IPersistent>>();
private Dictionary<Guid, IPersistent> persistentProxies = new Dictionary<Guid, IPersistent>();
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<Guid>();
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<IPersistent> 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<Guid, byte[]> persistentBytes = new Dictionary<Guid, byte[]>();
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<IPersistent> target = null;
public LazyInterceptor(ODB odb, Guid persistentID)
{
this.odb = odb;
}
public void Intercept(IInvocation invocation)
{
object t = target;
throw new NotImplementedException();
}
}
}
}