2019-03-13 08:22:08 +01:00
|
|
|
|
// /**
|
|
|
|
|
// * 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;
|
2019-03-20 14:28:56 +01:00
|
|
|
|
using Castle.DynamicProxy;
|
|
|
|
|
using ln.types.serialize;
|
|
|
|
|
using Castle.Components.DictionaryAdapter;
|
|
|
|
|
using System.Linq;
|
2019-03-13 08:22:08 +01:00
|
|
|
|
namespace ln.types.odb
|
|
|
|
|
{
|
2019-03-20 14:28:56 +01:00
|
|
|
|
public class ODB<T> : ODB
|
|
|
|
|
{
|
|
|
|
|
public T Root
|
|
|
|
|
{
|
|
|
|
|
get => (T)RootObject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ODB(String basePath)
|
|
|
|
|
:base(basePath, typeof(T))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 08:22:08 +01:00
|
|
|
|
public class ODB
|
|
|
|
|
{
|
2019-03-20 14:28:56 +01:00
|
|
|
|
public object RootObject { get; protected set; }
|
2019-03-13 08:22:08 +01:00
|
|
|
|
|
2019-03-20 14:28:56 +01:00
|
|
|
|
public String BasePath { get; set; }
|
2019-03-13 08:22:08 +01:00
|
|
|
|
|
2019-03-20 14:28:56 +01:00
|
|
|
|
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>();
|
2019-03-13 08:22:08 +01:00
|
|
|
|
|
2019-03-20 14:28:56 +01:00
|
|
|
|
private Type RootType;
|
2019-03-13 08:22:08 +01:00
|
|
|
|
|
2019-03-20 14:28:56 +01:00
|
|
|
|
public ODB(string basePath)
|
2019-03-13 08:22:08 +01:00
|
|
|
|
{
|
2019-03-20 14:28:56 +01:00
|
|
|
|
BasePath = Path.GetFullPath(basePath);
|
2019-03-13 08:22:08 +01:00
|
|
|
|
if (!Directory.Exists(BasePath))
|
|
|
|
|
{
|
|
|
|
|
Directory.CreateDirectory(BasePath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-20 14:28:56 +01:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IPersistent LoadPersistent(Guid guid)
|
|
|
|
|
{
|
|
|
|
|
IPersistent o = GetCachedPersistent(guid);
|
|
|
|
|
if (o == null)
|
|
|
|
|
{
|
|
|
|
|
// ToDO: Implement Loading...
|
|
|
|
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
return o;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SavePersistent(IPersistent o) => SavePersistent(o, true);
|
|
|
|
|
void SavePersistent(IPersistent o,bool recurse)
|
|
|
|
|
{
|
|
|
|
|
MemoryStream objectStream = new MemoryStream();
|
|
|
|
|
ODBObjectWriter objectWriter = new ODBObjectWriter(this, objectStream);
|
|
|
|
|
objectWriter.Write(o);
|
|
|
|
|
|
|
|
|
|
byte[] persistentBytes = objectStream.ToArray();
|
|
|
|
|
IPersistent[] referencedObjects = objectWriter.ReferencedPersistents;
|
|
|
|
|
|
|
|
|
|
if (recurse)
|
|
|
|
|
{
|
|
|
|
|
// Todo: Implement Recursive Object Save
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
*
|
|
|
|
|
**/
|
2019-03-13 08:22:08 +01:00
|
|
|
|
public IPersistent GetPersistent(Guid persistenceID)
|
|
|
|
|
{
|
2019-03-20 14:28:56 +01:00
|
|
|
|
if (Guid.Empty.Equals(persistenceID))
|
|
|
|
|
return null;
|
|
|
|
|
|
2019-03-13 08:22:08 +01:00
|
|
|
|
if (persistentObjects.ContainsKey(persistenceID))
|
|
|
|
|
{
|
2019-03-20 14:28:56 +01:00
|
|
|
|
IPersistent o = GetCachedPersistent(persistenceID);
|
|
|
|
|
|
|
|
|
|
if (o == null)
|
|
|
|
|
{
|
|
|
|
|
}
|
2019-03-13 08:22:08 +01:00
|
|
|
|
|
2019-03-20 14:28:56 +01:00
|
|
|
|
return o;
|
2019-03-13 08:22:08 +01:00
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-20 14:28:56 +01:00
|
|
|
|
public PT GetProxy<PT>(Guid persistentID) where PT : IPersistent
|
|
|
|
|
{
|
|
|
|
|
return default(PT);
|
|
|
|
|
}
|
|
|
|
|
public IPersistent GetProxy(Type type, Guid persistenceID)
|
|
|
|
|
{
|
|
|
|
|
LazyInterceptor lazyInterceptor = new LazyInterceptor(this, persistenceID);
|
|
|
|
|
IPersistent persistent = proxyGenerator.CreateInterfaceProxyWithoutTarget(type, lazyInterceptor) as IPersistent;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return persistent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ODBObjectWriter : ObjectWriter
|
|
|
|
|
{
|
|
|
|
|
public ODB ODB { get; }
|
|
|
|
|
public IPersistent[] ReferencedPersistents => referencedPersistents.Values.ToArray();
|
|
|
|
|
|
|
|
|
|
private Dictionary<Guid, IPersistent> referencedPersistents = new Dictionary<Guid, IPersistent>();
|
|
|
|
|
|
|
|
|
|
public ODBObjectWriter(ODB odb,Stream stream)
|
|
|
|
|
:base(stream)
|
|
|
|
|
{
|
|
|
|
|
ODB = odb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override object QueryReference(object o)
|
|
|
|
|
{
|
|
|
|
|
if (o is IPersistent)
|
|
|
|
|
{
|
|
|
|
|
IPersistent persistent = o as IPersistent;
|
|
|
|
|
Guid persistenceID = persistent.GetPersistenceID();
|
|
|
|
|
|
|
|
|
|
if (!referencedPersistents.ContainsKey(persistenceID))
|
|
|
|
|
referencedPersistents.Add(persistenceID, persistent);
|
|
|
|
|
|
|
|
|
|
return persistenceID;
|
|
|
|
|
}
|
|
|
|
|
return o;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class ODBObjectReader : ObjectReader
|
|
|
|
|
{
|
|
|
|
|
public ODB ODB { get; }
|
2019-03-13 08:22:08 +01:00
|
|
|
|
|
2019-03-20 14:28:56 +01:00
|
|
|
|
public ODBObjectReader(ODB odb,Stream stream):
|
|
|
|
|
base(stream)
|
|
|
|
|
{
|
|
|
|
|
ODB = odb;
|
|
|
|
|
}
|
2019-03-13 08:22:08 +01:00
|
|
|
|
|
2019-03-20 14:28:56 +01:00
|
|
|
|
public override object QueryReferencedObject(object re)
|
|
|
|
|
{
|
|
|
|
|
if (re is Guid)
|
|
|
|
|
{
|
|
|
|
|
Guid persistenceID = (Guid)re;
|
|
|
|
|
IPersistent persistent = ODB.GetPersistent(persistenceID);
|
|
|
|
|
return persistent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return re;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-13 08:22:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|