WIP
parent
aa65fc9f4e
commit
035be47c45
43
CIDR.cs
43
CIDR.cs
|
@ -13,6 +13,7 @@ using System.Linq;
|
|||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using Newtonsoft.Json;
|
||||
using LiteDB;
|
||||
|
||||
namespace ln.types
|
||||
{
|
||||
|
@ -35,7 +36,7 @@ namespace ln.types
|
|||
return new CIDR(ip, w);
|
||||
}
|
||||
}
|
||||
return new CIDR(ip,32);
|
||||
return new CIDR(ip, 32);
|
||||
}
|
||||
|
||||
private readonly uint _ip;
|
||||
|
@ -45,7 +46,7 @@ namespace ln.types
|
|||
public CIDR Network => new CIDR(_ip & _netmask, _netmask);
|
||||
public CIDR Host => new CIDR(_ip, 0xffffffff);
|
||||
|
||||
public int Size => (1 << (32 - MaskWidth));
|
||||
public int Size => (1 << (32 - MaskWidth));
|
||||
|
||||
public byte[] IPBytes
|
||||
{
|
||||
|
@ -115,12 +116,12 @@ namespace ln.types
|
|||
|
||||
for (w = 32; w > 0; w--)
|
||||
{
|
||||
if ((nm & (1 << (int)(32-w))) != 0)
|
||||
if ((nm & (1 << (int)(32 - w))) != 0)
|
||||
break;
|
||||
}
|
||||
for (uint n = w; n > 0; n--)
|
||||
{
|
||||
if ((nm & (1 << (int)(32-n))) == 0)
|
||||
if ((nm & (1 << (int)(32 - n))) == 0)
|
||||
throw new FormatException("Netmask with holes");
|
||||
}
|
||||
|
||||
|
@ -136,7 +137,7 @@ namespace ln.types
|
|||
uint newmask = maskFromWidth((uint)(MaskWidth + bits));
|
||||
uint nip = _ip;
|
||||
CIDR[] result = new CIDR[count];
|
||||
for (int n=0;n<count;n++)
|
||||
for (int n = 0; n < count; n++)
|
||||
{
|
||||
nip += (uint)(1 << (32 - MaskWidth - bits));
|
||||
result[n] = new CIDR(nip, newmask);
|
||||
|
@ -150,23 +151,32 @@ namespace ln.types
|
|||
if (_netmask == 0xFFFFFFFF)
|
||||
return String.Format("{0}", String.Join(".", IPBytes.Select((x) => x.ToString())));
|
||||
else
|
||||
return String.Format("{0}/{1}", String.Join(".", IPBytes.Select((x) => x.ToString())),getNetWidth(_netmask));
|
||||
return String.Format("{0}/{1}", String.Join(".", IPBytes.Select((x) => x.ToString())), getNetWidth(_netmask));
|
||||
}
|
||||
|
||||
public static implicit operator IPAddress(CIDR cidr)
|
||||
{
|
||||
return new IPAddress( cidr.IPBytes );
|
||||
return new IPAddress(cidr.IPBytes);
|
||||
}
|
||||
public static implicit operator CIDR(IPAddress iPAddress)
|
||||
{
|
||||
return new CIDR(BitConverter.ToUInt32(iPAddress.GetAddressBytes().Reverse().ToArray(),0),0xFFFFFFFF);
|
||||
return new CIDR(BitConverter.ToUInt32(iPAddress.GetAddressBytes().Reverse().ToArray(), 0), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
public bool Contains(CIDR you)
|
||||
{
|
||||
return (you.MaskWidth >= MaskWidth) && ((you._ip & _netmask)==(_ip & _netmask));
|
||||
return (you.MaskWidth >= MaskWidth) && ((you._ip & _netmask) == (_ip & _netmask));
|
||||
}
|
||||
|
||||
public bool Contains(IEnumerable<CIDR> candidates)
|
||||
{
|
||||
foreach (CIDR ip in candidates)
|
||||
if (Contains(ip))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)(_ip ^ _netmask);
|
||||
|
@ -225,13 +235,17 @@ namespace ln.types
|
|||
}
|
||||
|
||||
|
||||
static bool ___init = ____init();
|
||||
static bool ____init()
|
||||
static CIDR()
|
||||
{
|
||||
BsonMapper.Global.RegisterType<CIDR>(
|
||||
serialize: (ip) => ip.ToString(),
|
||||
deserialize: (bson) => CIDR.Parse(bson.AsString)
|
||||
);
|
||||
|
||||
|
||||
List<JsonConverter> converters = new List<JsonConverter>();
|
||||
converters.Add(new CIDRJsonConverter());
|
||||
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = converters };
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -243,15 +257,16 @@ namespace ln.types
|
|||
return (objectType == typeof(CIDR));
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
|
||||
{
|
||||
return CIDR.Parse(reader.ReadAsString());
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue((value as CIDR).ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
namespace ln.types
|
||||
{
|
||||
public static class Extensions
|
||||
|
@ -14,5 +15,17 @@ namespace ln.types
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int ReadInteger(this Stream stream)
|
||||
{
|
||||
byte[] b = new byte[4];
|
||||
stream.Read(b, 0, 4);
|
||||
return BitConverter.ToInt32(b,0);
|
||||
}
|
||||
public static void WriteInteger(this Stream stream,int i)
|
||||
{
|
||||
stream.Write(BitConverter.GetBytes(i), 0, 4);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// /**
|
||||
// * File: GeoLocation.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;
|
||||
namespace ln.types
|
||||
{
|
||||
public struct GeoLocation
|
||||
{
|
||||
public double Latitude;
|
||||
public double Longitude;
|
||||
|
||||
public GeoLocation(double latitude,double longitude)
|
||||
{
|
||||
Latitude = latitude;
|
||||
Longitude = longitude;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0:F}{1}{2:F}{3}",
|
||||
(Latitude < 0) ? -Latitude : Latitude,
|
||||
(Latitude < 0) ? 'S':'N',
|
||||
(Longitude < 0) ? -Longitude : Longitude,
|
||||
(Longitude < 0) ? 'W' : 'E'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
// /**
|
||||
// * File: URI.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.Text;
|
||||
namespace ln.types
|
||||
{
|
||||
/**
|
||||
* Quick and Dirty RFC3986 URI
|
||||
*
|
||||
**/
|
||||
|
||||
public class URI
|
||||
{
|
||||
public String Scheme { get; private set; } = String.Empty;
|
||||
public String Authority { get; private set; } = String.Empty;
|
||||
|
||||
public String[] UserInfo { get; private set; } = new String[0];
|
||||
public String Host { get; private set; } = String.Empty;
|
||||
public String Port { get; private set; } = String.Empty;
|
||||
|
||||
public String Path { get; private set; } = String.Empty;
|
||||
public String Query { get; private set; } = String.Empty;
|
||||
public String Fragment { get; private set; } = String.Empty;
|
||||
|
||||
private URI()
|
||||
{
|
||||
}
|
||||
|
||||
public URI(String uri)
|
||||
{
|
||||
Parse(uri);
|
||||
ParseAuthority();
|
||||
}
|
||||
public URI(String scheme, String authority, string path)
|
||||
{
|
||||
Parse(String.Format("{0}://{1}{2}", scheme, authority, path));
|
||||
ParseAuthority();
|
||||
}
|
||||
public URI(String scheme,String authority,string path,string query,string fragment)
|
||||
{
|
||||
Scheme = scheme;
|
||||
Authority = authority;
|
||||
Path = path;
|
||||
Query = query;
|
||||
Fragment = fragment;
|
||||
ParseAuthority();
|
||||
}
|
||||
|
||||
public URI(URI uri, string path)
|
||||
{
|
||||
Parse(String.Format("{0}://{1}{2}", uri.Scheme, uri.Authority, path));
|
||||
ParseAuthority();
|
||||
}
|
||||
|
||||
public URI Follow(String path)
|
||||
{
|
||||
if (path.StartsWith("/",StringComparison.InvariantCulture))
|
||||
{
|
||||
return new URI(Scheme, Authority, path);
|
||||
} else if (Path.EndsWith("/",StringComparison.InvariantCulture) || path.StartsWith("?",StringComparison.InvariantCulture) || path.StartsWith("#", StringComparison.InvariantCulture))
|
||||
{
|
||||
return new URI(Scheme, Authority, String.Format("{0}{1}", Path, path));
|
||||
}
|
||||
else
|
||||
{
|
||||
int indSlash = Path.LastIndexOf('/');
|
||||
return new URI(Scheme, Authority, String.Format("{0}/{1}",Path.Substring(0,indSlash),path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void Parse(String uri)
|
||||
{
|
||||
char[] chUri = uri.ToCharArray();
|
||||
int n = 0;
|
||||
int m = 0;
|
||||
|
||||
// Scheme
|
||||
|
||||
while ((chUri[n] != ':') && ((++n) < chUri.Length)) { };
|
||||
|
||||
if (n < 2)
|
||||
throw new FormatException(String.Format("URL malformed: {0}",uri));
|
||||
|
||||
Scheme = new string(chUri, 0, n);
|
||||
n++;
|
||||
|
||||
if (n < chUri.Length)
|
||||
{
|
||||
if ((chUri.Length - n > 1) && (chUri[n] == '/') && (chUri[n+1] == '/'))
|
||||
{
|
||||
// Authority
|
||||
n += 2;
|
||||
m = n;
|
||||
|
||||
while (
|
||||
(m < chUri.Length) &&
|
||||
(chUri[m] != '/') &&
|
||||
(chUri[m] != '?') &&
|
||||
(chUri[m] != '#')
|
||||
) { m++; }
|
||||
|
||||
Authority = new string(chUri, n, (m - n));
|
||||
n = m;
|
||||
}
|
||||
|
||||
// Path
|
||||
m = n;
|
||||
while (
|
||||
(m < chUri.Length) &&
|
||||
(chUri[m] != '?') &&
|
||||
(chUri[m] != '#')
|
||||
)
|
||||
{ m++; }
|
||||
|
||||
Path = new string(chUri, n, (m - n));
|
||||
n = m;
|
||||
|
||||
if (n < chUri.Length)
|
||||
{
|
||||
if (chUri[n] == '?')
|
||||
{
|
||||
n++;
|
||||
m = n;
|
||||
while (
|
||||
(m < chUri.Length) &&
|
||||
(chUri[m] != '#')
|
||||
)
|
||||
{ m++; }
|
||||
|
||||
Query = new string(chUri, n, (m - n));
|
||||
n = m;
|
||||
}
|
||||
if ((n<chUri.Length) && (chUri[n] == '#'))
|
||||
{
|
||||
n++;
|
||||
m = n;
|
||||
while (
|
||||
(m < chUri.Length) &&
|
||||
(chUri[m] != '#')
|
||||
)
|
||||
{ m++; }
|
||||
|
||||
Fragment = new string(chUri, n, (m - n));
|
||||
n = m;
|
||||
}
|
||||
|
||||
if (n < chUri.Length)
|
||||
throw new FormatException(String.Format("Malformed URI: {0}", uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseAuthority()
|
||||
{
|
||||
int indAt = Authority.IndexOf('@');
|
||||
if (indAt != -1)
|
||||
{
|
||||
UserInfo = Authority.Substring(0, indAt).Split(':');
|
||||
}
|
||||
indAt++;
|
||||
|
||||
int indPort = Authority.IndexOf(':', indAt);
|
||||
|
||||
if (indPort != -1)
|
||||
{
|
||||
Host = Authority.Substring(indAt, indPort - indAt);
|
||||
Port = Authority.Substring(indPort + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Host = Authority.Substring(indAt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.Append(Scheme);
|
||||
stringBuilder.Append(':');
|
||||
|
||||
if (!String.Empty.Equals(Authority))
|
||||
{
|
||||
stringBuilder.Append("//");
|
||||
if (UserInfo.Length > 0)
|
||||
{
|
||||
stringBuilder.Append(UserInfo[0]);
|
||||
stringBuilder.Append('@');
|
||||
}
|
||||
|
||||
stringBuilder.Append(Host);
|
||||
|
||||
if (!String.Empty.Equals(Port))
|
||||
{
|
||||
stringBuilder.Append(':');
|
||||
stringBuilder.Append(Port);
|
||||
}
|
||||
}
|
||||
|
||||
stringBuilder.Append(Path);
|
||||
|
||||
if (!string.Empty.Equals(Query))
|
||||
{
|
||||
stringBuilder.Append("?");
|
||||
stringBuilder.Append(Query);
|
||||
}
|
||||
if (!string.Empty.Equals(Fragment))
|
||||
{
|
||||
stringBuilder.Append('#');
|
||||
stringBuilder.Append(Fragment);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
private int GetHashCode(String s)
|
||||
{
|
||||
return (s == null) ? -1 : s.GetHashCode();
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return GetHashCode(Scheme) ^ GetHashCode(Authority) ^ GetHashCode(Path) ^ GetHashCode(Query) ^ GetHashCode(Fragment);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is URI)
|
||||
{
|
||||
URI other = obj as URI;
|
||||
return Scheme.Equals(other.Scheme) && Authority.Equals(other.Authority) && Path.Equals(other.Path) && Query.Equals(other.Query) && Fragment.Equals(other.Fragment);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -38,6 +38,9 @@
|
|||
<HintPath>..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="LiteDB">
|
||||
<HintPath>..\packages\LiteDB.4.1.4\lib\net40\LiteDB.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
@ -60,12 +63,30 @@
|
|||
<Compile Include="odb\ODBFileStorage.cs" />
|
||||
<Compile Include="odb\Storage.cs" />
|
||||
<Compile Include="Extensions.cs" />
|
||||
<Compile Include="GeoLocation.cs" />
|
||||
<Compile Include="URI.cs" />
|
||||
<Compile Include="odb\ODBCollection.cs" />
|
||||
<Compile Include="odb\ODBDocument.cs" />
|
||||
<Compile Include="odb\values\ODBGuid.cs" />
|
||||
<Compile Include="odb\values\ODBNull.cs" />
|
||||
<Compile Include="odb\values\ODBStringValue.cs" />
|
||||
<Compile Include="odb\values\ODBValue.cs" />
|
||||
<Compile Include="odb\values\ODBInteger.cs" />
|
||||
<Compile Include="odb\values\ODBLong.cs" />
|
||||
<Compile Include="odb\values\ODBDouble.cs" />
|
||||
<Compile Include="odb\ODBMapper.cs" />
|
||||
<Compile Include="odb\ClassMapping.cs" />
|
||||
<Compile Include="odb\values\ODBList.cs" />
|
||||
<Compile Include="odb\ListMapping.cs" />
|
||||
<Compile Include="odb\ODBCollection<>.cs" />
|
||||
<Compile Include="odb\DictionaryMapping.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="sync\" />
|
||||
<Folder Include="serialize\" />
|
||||
<Folder Include="odb\" />
|
||||
<Folder Include="threads\" />
|
||||
<Folder Include="odb\values\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ln.logging\ln.logging.csproj">
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using ln.types.odb.values;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using ln.logging;
|
||||
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class DocumentIDAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
public class ClassMapping : IODBMapping
|
||||
{
|
||||
public Type MappedType { get; }
|
||||
public String IDField { get; private set; }
|
||||
|
||||
List<FieldInfo> mappedFields = new List<FieldInfo>();
|
||||
|
||||
public ClassMapping(Type type)
|
||||
{
|
||||
Logging.Log(LogLevel.DEBUG, "Constructing ClassMapping for {0}",type);
|
||||
|
||||
MappedType = type;
|
||||
AddFields(type);
|
||||
}
|
||||
|
||||
private void AddFields(Type type)
|
||||
{
|
||||
foreach (FieldInfo fieldinfo in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
|
||||
{
|
||||
if (fieldinfo.GetCustomAttribute<IgnoreFieldAttribute>() == null)
|
||||
{
|
||||
mappedFields.Add(fieldinfo);
|
||||
if (fieldinfo.GetCustomAttribute<DocumentIDAttribute>() != null)
|
||||
{
|
||||
IDField = fieldinfo.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((type != null) && !type.IsValueType && (!typeof(object).Equals(type.BaseType)))
|
||||
{
|
||||
AddFields(type.BaseType);
|
||||
}
|
||||
}
|
||||
|
||||
public object UnmapValue(ODBMapper mapper,ODBValue oval)
|
||||
{
|
||||
ODBDocument document = oval as ODBDocument;
|
||||
object o = Activator.CreateInstance(MappedType, true);
|
||||
|
||||
foreach (FieldInfo fieldInfo in mappedFields)
|
||||
{
|
||||
object fv = ODBMapper.Default.UnmapValue(fieldInfo.FieldType,document[fieldInfo.Name]);
|
||||
fieldInfo.SetValue(o, fv);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
public ODBValue MapValue(ODBMapper mapper,object value)
|
||||
{
|
||||
ODBDocument document = new ODBDocument();
|
||||
document["__asm__"] = value.GetType().Assembly.GetName().Name;
|
||||
document["__type__"] = value.GetType().FullName;
|
||||
|
||||
foreach (FieldInfo fieldInfo in mappedFields)
|
||||
{
|
||||
object fv = fieldInfo.GetValue(value);
|
||||
ODBValue ov = ODBMapper.Default.MapValue(fv);
|
||||
document[fieldInfo.Name] = ov;
|
||||
}
|
||||
|
||||
if (IDField != null)
|
||||
{
|
||||
document.ID = document[IDField];
|
||||
}
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
||||
public class ObjectMapping : IODBMapping
|
||||
{
|
||||
|
||||
public ODBValue MapValue(ODBMapper mapper, object value)
|
||||
{
|
||||
return new ODBDocument();
|
||||
}
|
||||
|
||||
public object UnmapValue(ODBMapper mapper, ODBValue oval)
|
||||
{
|
||||
if (oval is ODBDocument)
|
||||
{
|
||||
|
||||
|
||||
ODBDocument document = oval.AsDocument;
|
||||
if (!document.Contains("__type__"))
|
||||
return new object();
|
||||
|
||||
Type dType = Assembly.Load(document["__asm__"].AsString).GetType(document["__type__"].AsString);
|
||||
return mapper.UnmapValue(dType, oval);
|
||||
}
|
||||
else
|
||||
{
|
||||
return oval.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using ln.types.odb.values;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using Castle.Components.DictionaryAdapter;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class DictionaryMapping : IODBMapping
|
||||
{
|
||||
public DictionaryMapping()
|
||||
{
|
||||
}
|
||||
|
||||
public ODBValue MapValue(ODBMapper mapper, object value)
|
||||
{
|
||||
Type dType = value.GetType();
|
||||
|
||||
if (dType.GetInterfaces().Contains(typeof(IDictionary)))
|
||||
{
|
||||
IDictionary dictionary = value as IDictionary;
|
||||
ODBDocument document = new ODBDocument();
|
||||
|
||||
document["__asm__"] = value.GetType().Assembly.GetName().Name;
|
||||
document["__type__"] = value.GetType().FullName;
|
||||
|
||||
foreach (object key in dictionary.Keys)
|
||||
{
|
||||
object v = dictionary[key];
|
||||
document[mapper.MapValue(key)] = mapper.MapValue(v);
|
||||
}
|
||||
return document;
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public object UnmapValue(ODBMapper mapper, ODBValue oval)
|
||||
{
|
||||
ODBDocument document = oval.AsDocument;
|
||||
Type dType = Assembly.Load(document["__asm__"].AsString).GetType(document["__type__"].AsString);
|
||||
|
||||
if (dType.IsGenericType)
|
||||
{
|
||||
IDictionary dictionary = (IDictionary)Activator.CreateInstance(dType, true);
|
||||
|
||||
if (dType.GetGenericTypeDefinition().Equals(typeof(Dictionary<,>)))
|
||||
{
|
||||
Type kType = dType.GetGenericArguments()[0];
|
||||
Type vType = dType.GetGenericArguments()[1];
|
||||
|
||||
foreach (ODBValue key in document.Keys)
|
||||
{
|
||||
if (!key.Equals("__asm__") && !key.Equals("__type__"))
|
||||
dictionary.Add(mapper.UnmapValue(kType, key), mapper.UnmapValue(vType, document[key]));
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// /**
|
||||
// * File: ListMapping.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 ln.types.odb.values;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class ListMapping : IODBMapping
|
||||
{
|
||||
public Type TargetType { get; }
|
||||
|
||||
public ListMapping(Type targetType)
|
||||
{
|
||||
TargetType = targetType;
|
||||
}
|
||||
|
||||
public object UnmapValue(ODBMapper mapper,ODBValue oval)
|
||||
{
|
||||
ODBList list = oval as ODBList;
|
||||
|
||||
if (TargetType.IsArray)
|
||||
{
|
||||
Array a = Array.CreateInstance(TargetType.GetElementType(), list.Count);
|
||||
for (int n = 0; n < list.Count; n++)
|
||||
a.SetValue(list[n], n);
|
||||
return a;
|
||||
} else if (TargetType.GetInterfaces().Contains(typeof(IList)))
|
||||
{
|
||||
IList ilist = (IList)Activator.CreateInstance(TargetType, true);
|
||||
for (int n = 0; n < list.Count; n++)
|
||||
ilist.Add(list[n]);
|
||||
return ilist;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ODBValue MapValue(ODBMapper mapper,object value)
|
||||
{
|
||||
ODBList list = new ODBList();
|
||||
|
||||
foreach (object item in (IEnumerable)value)
|
||||
{
|
||||
list.Add(ODBMapper.Default.MapValue(item));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
173
odb/ODB.cs
173
odb/ODB.cs
|
@ -14,165 +14,70 @@ using Castle.DynamicProxy;
|
|||
using ln.types.serialize;
|
||||
using Castle.Components.DictionaryAdapter;
|
||||
using System.Linq;
|
||||
using ln.logging;
|
||||
using ln.types.odb.values;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class ODB<T> : ODB where T: IPersistent
|
||||
{
|
||||
public T Root
|
||||
{
|
||||
get => (T)RootObject;
|
||||
}
|
||||
|
||||
public ODB(String basePath)
|
||||
:base(basePath, typeof(T))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ODB
|
||||
public class ODB : IDisposable
|
||||
{
|
||||
public String BasePath { get; set; }
|
||||
|
||||
public IPersistent RootObject { get; protected set; }
|
||||
|
||||
|
||||
private Type RootType;
|
||||
private Storage Storage { get; set; }
|
||||
|
||||
private Dictionary<Guid, PreparedObject> objectCache = new Dictionary<Guid, PreparedObject>();
|
||||
Dictionary<string, ODBCollection> collections = new Dictionary<string, ODBCollection>();
|
||||
|
||||
public ODB(string basePath)
|
||||
{
|
||||
BasePath = Path.GetFullPath(basePath);
|
||||
Storage = new ODBFileStorage(basePath);
|
||||
if (!Directory.Exists(BasePath))
|
||||
Directory.CreateDirectory(BasePath);
|
||||
}
|
||||
|
||||
public ODB(String basePath, Type rootType)
|
||||
: this(basePath)
|
||||
public ODBCollection GetCollection(string colName)
|
||||
{
|
||||
RootType = rootType;
|
||||
Initialize();
|
||||
if (!collections.ContainsKey(colName))
|
||||
collections[colName] = new ODBCollection(this, colName);
|
||||
|
||||
return collections[colName];
|
||||
}
|
||||
public ODB(String basePath,IPersistent rootObject)
|
||||
: this(basePath)
|
||||
|
||||
public ODBCollection<T> GetCollection<T>() where T:class
|
||||
{
|
||||
RootType = rootObject.GetType();
|
||||
RootObject = rootObject;
|
||||
Initialize();
|
||||
return new ODBCollection<T>(this);
|
||||
}
|
||||
|
||||
|
||||
internal void DisposeCollection(ODBCollection collection)
|
||||
{
|
||||
ODBCollection check = collections[collection.CollectionName];
|
||||
if (check == collection)
|
||||
collections.Remove(collection.CollectionName);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
if (RootObject == null)
|
||||
{
|
||||
string rootHint = Path.Combine(BasePath, "root.hint");
|
||||
if (File.Exists(rootHint))
|
||||
{
|
||||
string rootID = File.ReadAllText(rootHint);
|
||||
Guid persistenceID = Guid.Parse(rootID);
|
||||
RootObject = LoadPersistent(persistenceID);
|
||||
}
|
||||
else
|
||||
{
|
||||
RootObject = (IPersistent)Activator.CreateInstance(RootType);
|
||||
string rootID = RootObject.GetPersistenceID().ToString();
|
||||
SavePersistent(RootObject);
|
||||
File.WriteAllText(rootHint, rootID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(Guid persistenceID)
|
||||
public void Dispose()
|
||||
{
|
||||
return Storage.Contains(persistenceID) || objectCache.ContainsKey(persistenceID);
|
||||
foreach (ODBCollection col in collections.Values.ToArray())
|
||||
{
|
||||
col.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SavePersistent(IPersistent o) => SavePersistent(o, true);
|
||||
public void SavePersistent(IPersistent o,bool recurse)
|
||||
static ODB()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
SaveCollector saveCollector = new SaveCollector(this);
|
||||
saveCollector.Add(o);
|
||||
|
||||
foreach (PreparedObject preparedObject in saveCollector.PreparedToSave)
|
||||
{
|
||||
Storage.Store(preparedObject);
|
||||
objectCache[preparedObject.PersistenceID] = preparedObject;
|
||||
}
|
||||
}
|
||||
new ODBDocument();
|
||||
new ODBNull();
|
||||
new ODBStringValue();
|
||||
new ODBList();
|
||||
new ODBInteger();
|
||||
new ODBUInteger();
|
||||
new ODBLong();
|
||||
new ODBULong();
|
||||
new ODBDouble();
|
||||
new ODBGuid();
|
||||
}
|
||||
|
||||
public T LoadPersistent<T>(Guid persistenceID) => (T)LoadPersistent(persistenceID);
|
||||
public IPersistent LoadPersistent(Guid persistenceID)
|
||||
{
|
||||
if (!Contains(persistenceID))
|
||||
throw new KeyNotFoundException();
|
||||
|
||||
PreparedObject preparedObject = GetCachedPersistent(persistenceID);
|
||||
if (preparedObject == null)
|
||||
{
|
||||
preparedObject = new PreparedObject(this, typeof(IPersistent), persistenceID);
|
||||
if (!Storage.Load(preparedObject))
|
||||
throw new IOException(String.Format("unable to load IPersistent({0})",persistenceID));
|
||||
|
||||
preparedObject.CreateInstance();
|
||||
objectCache.Add(persistenceID,preparedObject);
|
||||
}
|
||||
|
||||
return preparedObject.Instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private PreparedObject GetCachedPersistent(Guid persistenceID)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (objectCache.ContainsKey(persistenceID))
|
||||
{
|
||||
return objectCache[persistenceID];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
class SaveCollector
|
||||
{
|
||||
public ODB ODB { get; }
|
||||
|
||||
public IEnumerable<PreparedObject> PreparedToSave => preparedObjects.Values;
|
||||
|
||||
private Dictionary<Guid, PreparedObject> preparedObjects = new Dictionary<Guid, PreparedObject>();
|
||||
|
||||
public SaveCollector(ODB odb)
|
||||
{
|
||||
ODB = odb;
|
||||
}
|
||||
|
||||
public void Add(IPersistent persistent)
|
||||
{
|
||||
PreparedObject preparedObject = new PreparedObject(ODB,persistent);
|
||||
PreparedObject cachedObject = ODB.GetCachedPersistent(preparedObject.PersistenceID);
|
||||
|
||||
if (!preparedObject.InstanceEquals(cachedObject) && !preparedObjects.ContainsKey(preparedObject.PersistenceID))
|
||||
{
|
||||
preparedObjects.Add(preparedObject.PersistenceID, preparedObject);
|
||||
|
||||
foreach (IPersistent referencedPersistent in preparedObject.ReferencedPersistents)
|
||||
{
|
||||
Add(referencedPersistent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,419 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ln.types.odb.values;
|
||||
using System.IO;
|
||||
using System.Net.Mime;
|
||||
using System.Security.AccessControl;
|
||||
using System.Linq;
|
||||
using System.ComponentModel.Design.Serialization;
|
||||
using System.ComponentModel;
|
||||
using ln.logging;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class ODBCollection : IEnumerable<ODBDocument>, IDisposable
|
||||
{
|
||||
public ODB ODB { get; }
|
||||
public String CollectionName { get; }
|
||||
|
||||
public DocumentIndex Index => documentIndex;
|
||||
|
||||
FileStream fileStream;
|
||||
DocumentIndex documentIndex;
|
||||
|
||||
internal ODBCollection(ODB odb,string collectionName)
|
||||
{
|
||||
ODB = odb;
|
||||
CollectionName = collectionName;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
fileStream = new FileStream(Path.Combine(ODB.BasePath, String.Format("{0}.col",CollectionName)),FileMode.OpenOrCreate,FileAccess.ReadWrite);
|
||||
documentIndex = new DocumentIndex(fileStream);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public bool Insert(ODBDocument document)
|
||||
{
|
||||
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID);
|
||||
if (die == null)
|
||||
{
|
||||
byte[] docBytes = document.ToStorage();
|
||||
die = documentIndex.FindUnused(docBytes.Length);
|
||||
|
||||
die.Update(document.ID,docBytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public bool Update(ODBDocument document)
|
||||
{
|
||||
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID);
|
||||
if (die != null)
|
||||
{
|
||||
byte[] docBytes = document.ToStorage();
|
||||
if (die.BufferLength < docBytes.Length)
|
||||
{
|
||||
DocumentIndex.DocumentIndexEntry ndie = documentIndex.FindUnused(docBytes.Length);
|
||||
die.DocumentID = ODBNull.Instance;
|
||||
ndie.Update(document.ID, docBytes);
|
||||
die.Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
die.Update(document.ID, docBytes);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public bool Upsert(ODBDocument document)
|
||||
{
|
||||
byte[] docBytes = document.ToStorage();
|
||||
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID);
|
||||
DocumentIndex.DocumentIndexEntry rdie = null;
|
||||
|
||||
if ((die == null) || (die.BufferLength < docBytes.Length))
|
||||
{
|
||||
rdie = die;
|
||||
die = documentIndex.FindUnused(docBytes.Length);
|
||||
}
|
||||
if (rdie != null)
|
||||
rdie.DocumentID = ODBNull.Instance;
|
||||
die.Update(document.ID, docBytes);
|
||||
if (rdie != null)
|
||||
rdie.Release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public ODBDocument GetDocumentByID(ODBValue id)
|
||||
{
|
||||
Logging.Log(LogLevel.DEBUG, "ODBCollection.GetDocumentByID(): {0}",id);
|
||||
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(id);
|
||||
if (die != null)
|
||||
{
|
||||
byte[] storageBytes = die.ReadStorageBytes();
|
||||
ODBDocument document = new ODBDocument(storageBytes, 0, storageBytes.Length);
|
||||
return document;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<ODBDocument> Find(string propertyName, ODBValue value)
|
||||
{
|
||||
foreach (ODBDocument document in this)
|
||||
{
|
||||
if (value.Equals(document[propertyName]))
|
||||
yield return document;
|
||||
}
|
||||
}
|
||||
public ODBDocument FindOne(string propertyName, ODBValue value)
|
||||
{
|
||||
foreach (ODBDocument document in this)
|
||||
{
|
||||
if (value.Equals(document[propertyName]))
|
||||
return document;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public IEnumerator<ODBDocument> GetEnumerator()
|
||||
{
|
||||
foreach (ODBValue id in documentIndex.ToArray())
|
||||
{
|
||||
yield return GetDocumentByID(id);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ODB.DisposeCollection(this);
|
||||
|
||||
if (fileStream != null)
|
||||
{
|
||||
fileStream.Dispose();
|
||||
fileStream = null;
|
||||
}
|
||||
|
||||
documentIndex = null;
|
||||
}
|
||||
|
||||
|
||||
public class DocumentIndex : IEnumerable<ODBValue>
|
||||
{
|
||||
public Stream StorageStream { get; }
|
||||
public DocumentIndexEntry Head { get; private set; }
|
||||
|
||||
private Dictionary<ODBValue, DocumentIndexEntry> idLookup = new Dictionary<ODBValue, DocumentIndexEntry>();
|
||||
|
||||
public DocumentIndex(Stream stream)
|
||||
{
|
||||
StorageStream = stream;
|
||||
Head = new DocumentIndexEntry(this);
|
||||
}
|
||||
|
||||
public IEnumerable<DocumentIndexEntry> IndexEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
DocumentIndexEntry entry = Head;
|
||||
while (entry != null)
|
||||
{
|
||||
yield return entry;
|
||||
entry = entry.Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DocumentIndexEntry Lookup(ODBValue ID)
|
||||
{
|
||||
foreach (DocumentIndexEntry die in IndexEntries)
|
||||
{
|
||||
if (ID.Equals(die.DocumentID))
|
||||
return die;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public DocumentIndexEntry FindUnused(int minLength)
|
||||
{
|
||||
foreach (DocumentIndexEntry die in IndexEntries)
|
||||
{
|
||||
if (die.IsUnused && (die.BufferLength > minLength))
|
||||
return die;
|
||||
if (die.Next == null)
|
||||
return die.Extend(minLength);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public class DocumentIndexEntry
|
||||
{
|
||||
public DocumentIndex Index { get; }
|
||||
|
||||
public DocumentIndexEntry Next { get; private set; }
|
||||
public DocumentIndexEntry Last { get; private set; }
|
||||
|
||||
public long Offset { get; private set; }
|
||||
public int BufferLength { get; private set; }
|
||||
|
||||
public long NextOffset => Offset + BufferLength + 4;
|
||||
|
||||
private ODBValue documentID;
|
||||
public ODBValue DocumentID
|
||||
{
|
||||
get => documentID;
|
||||
set
|
||||
{
|
||||
lock (Index)
|
||||
{
|
||||
if (!ODBNull.Instance.Equals(documentID))
|
||||
{
|
||||
Index.idLookup.Remove(documentID);
|
||||
}
|
||||
documentID = value;
|
||||
if (!ODBNull.Instance.Equals(documentID))
|
||||
{
|
||||
Index.idLookup.Add(documentID, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsUnused => (ODBNull.Instance.Equals(documentID));
|
||||
|
||||
public DocumentIndexEntry(DocumentIndex index)
|
||||
: this(index, 0)
|
||||
{ }
|
||||
private DocumentIndexEntry(DocumentIndex index, long offset)
|
||||
{
|
||||
Index = index;
|
||||
Offset = offset;
|
||||
Read();
|
||||
}
|
||||
|
||||
private DocumentIndexEntry(DocumentIndexEntry lastEntry,int bufferLength)
|
||||
{
|
||||
Last = lastEntry;
|
||||
Last.Next = this;
|
||||
|
||||
Index = lastEntry.Index;
|
||||
Offset = lastEntry.NextOffset;
|
||||
BufferLength = bufferLength;
|
||||
|
||||
WriteHeader();
|
||||
Release();
|
||||
}
|
||||
private DocumentIndexEntry(DocumentIndexEntry lastEntry)
|
||||
{
|
||||
Last = lastEntry;
|
||||
Index = lastEntry.Index;
|
||||
Offset = lastEntry.NextOffset;
|
||||
|
||||
if (Last.Next != null)
|
||||
{
|
||||
Next = Last.Next;
|
||||
Last.Next = this;
|
||||
Next.Last = this;
|
||||
|
||||
BufferLength = (int)(Next.Offset - Offset - 4);
|
||||
WriteHeader();
|
||||
Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
Last.Next = this;
|
||||
Read();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void Read()
|
||||
{
|
||||
lock (Index)
|
||||
{
|
||||
if (Offset >= Index.StorageStream.Length)
|
||||
{
|
||||
BufferLength = 0;
|
||||
DocumentID = ODBNull.Instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
Index.StorageStream.Position = Offset;
|
||||
BufferLength = Index.StorageStream.ReadInteger();
|
||||
|
||||
Index.StorageStream.Position = Offset + 4;
|
||||
|
||||
DocumentID = ODBValue.Read(Index.StorageStream);
|
||||
|
||||
if (NextOffset < Index.StorageStream.Length)
|
||||
{
|
||||
Next = new DocumentIndexEntry(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(ODBValue id,byte[] storageBytes)
|
||||
{
|
||||
lock (Index)
|
||||
{
|
||||
if (BufferLength < storageBytes.Length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
if (BufferLength > (storageBytes.Length + 32))
|
||||
{
|
||||
Split(storageBytes.Length);
|
||||
}
|
||||
|
||||
Index.StorageStream.Position = Offset + 4;
|
||||
Index.StorageStream.Write(storageBytes, 0, storageBytes.Length);
|
||||
DocumentID = id;
|
||||
}
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
lock (Index)
|
||||
{
|
||||
DocumentID = ODBNull.Instance;
|
||||
|
||||
Index.StorageStream.Position = Offset + 4;
|
||||
Index.StorageStream.Write(new byte[BufferLength], 0, BufferLength);
|
||||
|
||||
if ((Next != null) && Next.IsUnused)
|
||||
{
|
||||
Combine();
|
||||
}
|
||||
if ((Last != null) && Last.IsUnused)
|
||||
{
|
||||
Last.Combine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DocumentIndexEntry Extend(int length)
|
||||
{
|
||||
if (Next == null)
|
||||
{
|
||||
if ((Last == null) && (IsUnused))
|
||||
{
|
||||
BufferLength = length;
|
||||
|
||||
WriteHeader();
|
||||
Release();
|
||||
|
||||
return this;
|
||||
}
|
||||
return new DocumentIndexEntry(this, length);
|
||||
}
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
private void Split(int length)
|
||||
{
|
||||
BufferLength = length;
|
||||
DocumentIndexEntry dieInsert = new DocumentIndexEntry(this);
|
||||
WriteHeader();
|
||||
}
|
||||
private void Combine()
|
||||
{
|
||||
BufferLength += Next.BufferLength + 4;
|
||||
|
||||
Next = Next.Next;
|
||||
if (Next != null)
|
||||
Next.Last = this;
|
||||
|
||||
WriteHeader();
|
||||
}
|
||||
|
||||
private void WriteHeader()
|
||||
{
|
||||
lock (Index)
|
||||
{
|
||||
Index.StorageStream.Position = Offset;
|
||||
Index.StorageStream.WriteInteger(BufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ReadStorageBytes()
|
||||
{
|
||||
byte[] buffer = new byte[BufferLength];
|
||||
lock (Index)
|
||||
{
|
||||
Index.StorageStream.Position = Offset + 4;
|
||||
Index.StorageStream.Read(buffer, 0, BufferLength);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<ODBValue> GetEnumerator()
|
||||
{
|
||||
return idLookup.Keys.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ln.types.odb.values;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class ODBCollection<T> : IEnumerable<T> where T:class
|
||||
{
|
||||
public ODB ODB { get; }
|
||||
public Type ElementType { get; }
|
||||
|
||||
ODBCollection collection;
|
||||
Dictionary<ODBValue, WeakReference<T>> objectCache = new Dictionary<ODBValue, WeakReference<T>>();
|
||||
|
||||
internal ODBCollection(ODB odb)
|
||||
{
|
||||
ODB = odb;
|
||||
ElementType = typeof(T);
|
||||
collection = new ODBCollection(odb, ElementType.FullName);
|
||||
}
|
||||
|
||||
public T this[ODBValue documentID]
|
||||
{
|
||||
get => Select(documentID);
|
||||
}
|
||||
|
||||
|
||||
public T GetCachedObject(ODBValue documentID)
|
||||
{
|
||||
if (objectCache.ContainsKey(documentID))
|
||||
{
|
||||
T o = null;
|
||||
if (objectCache[documentID].TryGetTarget(out o))
|
||||
return o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void TouchCache(ODBValue documentID,T o)
|
||||
{
|
||||
if ((o == null)&&objectCache.ContainsKey(documentID))
|
||||
{
|
||||
objectCache.Remove(documentID);
|
||||
}
|
||||
else if (o != null)
|
||||
{
|
||||
objectCache[documentID] = new WeakReference<T>(o);
|
||||
}
|
||||
}
|
||||
|
||||
public T SelectOne(string fieldName, object value)
|
||||
{
|
||||
ODBDocument document = collection.FindOne(fieldName, ODBMapper.Default.MapValue(value));
|
||||
if (document != null)
|
||||
{
|
||||
return Select(document.ID);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public IEnumerable<T> Select(string fieldName, object value)
|
||||
{
|
||||
foreach (ODBDocument document in collection.Find(fieldName, ODBMapper.Default.MapValue(value)))
|
||||
{
|
||||
yield return Select(document.ID);
|
||||
}
|
||||
}
|
||||
|
||||
public T Select(ODBValue documentID)
|
||||
{
|
||||
T o = GetCachedObject(documentID);
|
||||
if (o == null)
|
||||
{
|
||||
ODBDocument document = collection.GetDocumentByID(documentID);
|
||||
o = ODBMapper.Default.ToNativeValue<T>(document);
|
||||
TouchCache(documentID, o);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
public bool Insert(T o)
|
||||
{
|
||||
ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument;
|
||||
return collection.Insert(document);
|
||||
}
|
||||
public bool Update(T o)
|
||||
{
|
||||
ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument;
|
||||
return collection.Update(document);
|
||||
}
|
||||
public bool Upsert(T o)
|
||||
{
|
||||
ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument;
|
||||
return collection.Upsert(document);
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
foreach (ODBValue documentID in collection.Index)
|
||||
{
|
||||
yield return Select(documentID);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ln.types.odb.values;
|
||||
using System.Linq;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class ODBDocument : ODBValue
|
||||
{
|
||||
private Dictionary<ODBValue, ODBValue> properties = new Dictionary<ODBValue, ODBValue>();
|
||||
|
||||
public ODBDocument()
|
||||
:base(0x1000)
|
||||
{
|
||||
}
|
||||
|
||||
public ODBValue ID { get; set; } = new ODBGuid();
|
||||
|
||||
public ODBDocument(byte[] bytes,int offset,int length)
|
||||
:this()
|
||||
{
|
||||
int endOffset = offset + length;
|
||||
|
||||
ID = ODBValue.Deserialize(bytes, ref offset);
|
||||
int nProps = BitConverter.ToInt32(bytes, offset);
|
||||
offset += 4;
|
||||
|
||||
for (int n=0;n<nProps;n++)
|
||||
{
|
||||
ODBStringValue propName = ODBValue.Deserialize(bytes,ref offset) as ODBStringValue;
|
||||
ODBValue propValue = ODBValue.Deserialize(bytes, ref offset);
|
||||
properties.Add(propName, propValue);
|
||||
}
|
||||
|
||||
if (offset > endOffset)
|
||||
throw new FormatException("ODBDocument deserialization read behind end of buffer");
|
||||
}
|
||||
|
||||
public ODBValue this[ODBValue propName]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (properties.ContainsKey(propName))
|
||||
return properties[propName];
|
||||
return ODBNull.Instance;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (ODBNull.Instance.Equals(value) && properties.ContainsKey(propName))
|
||||
{
|
||||
properties.Remove(propName);
|
||||
}
|
||||
else
|
||||
{
|
||||
properties[propName] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ODBValue> Keys => properties.Keys;
|
||||
|
||||
public bool Contains(ODBStringValue propName)
|
||||
{
|
||||
return !ODBNull.Instance.Equals(this[propName]);
|
||||
}
|
||||
|
||||
public override byte[] ToStorage()
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
BinaryWriter writer = new BinaryWriter(stream);
|
||||
|
||||
ID.Store(writer);
|
||||
writer.Write(properties.Count);
|
||||
|
||||
foreach (ODBStringValue propName in properties.Keys)
|
||||
{
|
||||
ODBValue propValue = properties[propName];
|
||||
propName.Store(writer);
|
||||
propValue.Store(writer);
|
||||
}
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("[ODBDocument ID={0} {1}]", ID.ToString(),String.Join(" ",properties.Select(kv=> String.Format("{0}={1}",kv.Key,kv.Value))));
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ID.GetHashCode();
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is ODBDocument)
|
||||
{
|
||||
ODBDocument you = obj as ODBDocument;
|
||||
return ID.Equals(you.ID);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static ODBDocument()
|
||||
{
|
||||
RegisterDeserializer(0x1000, (b,o,l) => new ODBDocument(b,o,l));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,135 +17,143 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class ODBFileStorage : Storage
|
||||
{
|
||||
public String BasePath { get; set; }
|
||||
public int StorageVersion { get; } = 0x01;
|
||||
//public class ODBFileStorage : Storage
|
||||
//{
|
||||
// public String BasePath { get; set; }
|
||||
// public int StorageVersion { get; } = 0x01;
|
||||
|
||||
public ODBFileStorage(string basePath)
|
||||
{
|
||||
BasePath = Path.GetFullPath(basePath);
|
||||
if (!Directory.Exists(BasePath))
|
||||
{
|
||||
Directory.CreateDirectory(BasePath);
|
||||
}
|
||||
}
|
||||
// public ODBFileStorage(string basePath)
|
||||
// {
|
||||
// BasePath = Path.GetFullPath(basePath);
|
||||
// if (!Directory.Exists(BasePath))
|
||||
// {
|
||||
// Directory.CreateDirectory(BasePath);
|
||||
// }
|
||||
// }
|
||||
|
||||
private string GetPersistentPath(Guid persistenceID)
|
||||
{
|
||||
byte[] idBytes = persistenceID.ToByteArray();
|
||||
return Path.Combine(BasePath, BitConverter.ToString(idBytes, 0, 4));
|
||||
}
|
||||
// private string GetPersistentPath(Guid persistenceID)
|
||||
// {
|
||||
// byte[] idBytes = persistenceID.ToByteArray();
|
||||
// return Path.Combine(BasePath, BitConverter.ToString(idBytes, 0, 4));
|
||||
// }
|
||||
|
||||
|
||||
|
||||
public override bool Contains(Guid persistenceID)
|
||||
{
|
||||
string fn = Path.Combine(GetPersistentPath(persistenceID), String.Format("{0}.0", persistenceID));
|
||||
return File.Exists(fn);
|
||||
}
|
||||
// public override bool Contains(Guid persistenceID)
|
||||
// {
|
||||
// string fn = Path.Combine(GetPersistentPath(persistenceID), String.Format("{0}.0", persistenceID));
|
||||
// return File.Exists(fn);
|
||||
// }
|
||||
|
||||
public override bool Store(PreparedObject preparedObject)
|
||||
{
|
||||
string targetPath = GetPersistentPath(preparedObject.PersistenceID);
|
||||
String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
|
||||
// public override bool Store(PreparedObject preparedObject)
|
||||
// {
|
||||
// string targetPath = GetPersistentPath(preparedObject.PersistenceID);
|
||||
// String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
|
||||
|
||||
if (!Directory.Exists(targetPath))
|
||||
Directory.CreateDirectory(targetPath);
|
||||
// if (!Directory.Exists(targetPath))
|
||||
// Directory.CreateDirectory(targetPath);
|
||||
|
||||
String fnn = String.Format("{0}.new", fnbase);
|
||||
// String fnn = String.Format("{0}.new", fnbase);
|
||||
|
||||
using (FileStream fs = new FileStream(fnn, FileMode.CreateNew))
|
||||
{
|
||||
ToStream(preparedObject, fs);
|
||||
fs.Close();
|
||||
}
|
||||
// if (File.Exists(fnn))
|
||||
// File.Delete(fnn);
|
||||
|
||||
for (int n = 5; n > 0; n--)
|
||||
{
|
||||
string fn1 = String.Format("{0}.{1}", fnbase, n - 1);
|
||||
string fn2 = String.Format("{0}.{1}", fnbase, n);
|
||||
// using (FileStream fs = new FileStream(fnn, FileMode.CreateNew))
|
||||
// {
|
||||
// ToStream(preparedObject, fs);
|
||||
// fs.Close();
|
||||
// }
|
||||
|
||||
if (File.Exists(fn1))
|
||||
File.Move(fn1, fn2);
|
||||
}
|
||||
// for (int n = 5; n > 0; n--)
|
||||
// {
|
||||
// string fn1 = String.Format("{0}.{1}", fnbase, n - 1);
|
||||
// string fn2 = String.Format("{0}.{1}", fnbase, n);
|
||||
|
||||
string fn = String.Format("{0}.{1}", fnbase, 0);
|
||||
File.Move(fnn, fn);
|
||||
// if (File.Exists(fn1))
|
||||
// {
|
||||
// if (File.Exists(fn2))
|
||||
// File.Delete(fn2);
|
||||
|
||||
return true;
|
||||
}
|
||||
// File.Move(fn1, fn2);
|
||||
// }
|
||||
// }
|
||||
|
||||
// string fn = String.Format("{0}.{1}", fnbase, 0);
|
||||
// File.Move(fnn, fn);
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
public override bool Load(PreparedObject preparedObject)
|
||||
{
|
||||
string targetPath = GetPersistentPath(preparedObject.PersistenceID);
|
||||
String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
|
||||
string fn = String.Format("{0}.0", fnbase);
|
||||
// public override bool Load(PreparedObject preparedObject)
|
||||
// {
|
||||
// string targetPath = GetPersistentPath(preparedObject.PersistenceID);
|
||||
// String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
|
||||
// string fn = String.Format("{0}.0", fnbase);
|
||||
|
||||
using (FileStream fs = new FileStream(fn, FileMode.Open))
|
||||
{
|
||||
FromStream(fs, preparedObject);
|
||||
fs.Close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// using (FileStream fs = new FileStream(fn, FileMode.Open))
|
||||
// {
|
||||
// FromStream(fs, preparedObject);
|
||||
// fs.Close();
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
private void ToStream(PreparedObject preparedObject,Stream stream)
|
||||
{
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
writer.Write(StorageVersion);
|
||||
writer.Write(DateTimeOffset.Now.ToUnixTimeMilliseconds());
|
||||
writer.Write(preparedObject.PreparedType.Assembly.FullName);
|
||||
writer.Write(preparedObject.PreparedType.FullName);
|
||||
// private void ToStream(PreparedObject preparedObject,Stream stream)
|
||||
// {
|
||||
// using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
// {
|
||||
// writer.Write(StorageVersion);
|
||||
// writer.Write(DateTimeOffset.Now.ToUnixTimeMilliseconds());
|
||||
// writer.Write(preparedObject.PreparedType.Assembly.GetName().Name);
|
||||
// writer.Write(preparedObject.PreparedType.FullName);
|
||||
|
||||
string[] fieldNames = preparedObject.StoredFieldNames;
|
||||
// string[] fieldNames = preparedObject.StoredFieldNames;
|
||||
|
||||
writer.Write(fieldNames.Length);
|
||||
foreach (String fieldName in fieldNames)
|
||||
{
|
||||
byte[] fieldBytes = preparedObject.GetFieldBytes(fieldName);
|
||||
writer.Write(fieldName);
|
||||
writer.Write(fieldBytes.Length);
|
||||
writer.Write(fieldBytes);
|
||||
}
|
||||
// writer.Write(fieldNames.Length);
|
||||
// foreach (String fieldName in fieldNames)
|
||||
// {
|
||||
// byte[] fieldBytes = preparedObject.GetFieldBytes(fieldName);
|
||||
// writer.Write(fieldName);
|
||||
// writer.Write(fieldBytes.Length);
|
||||
// writer.Write(fieldBytes);
|
||||
// }
|
||||
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
// writer.Close();
|
||||
// }
|
||||
// }
|
||||
|
||||
private void FromStream(Stream stream,PreparedObject preparedObject)
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(stream))
|
||||
{
|
||||
if (reader.ReadInt32() != StorageVersion)
|
||||
throw new FormatException("Unsupported Storage Version");
|
||||
// private void FromStream(Stream stream,PreparedObject preparedObject)
|
||||
// {
|
||||
// using (BinaryReader reader = new BinaryReader(stream))
|
||||
// {
|
||||
// if (reader.ReadInt32() != StorageVersion)
|
||||
// throw new FormatException("Unsupported Storage Version");
|
||||
|
||||
DateTime timestamp = DateTimeOffset.FromUnixTimeMilliseconds(reader.ReadInt64()).DateTime;
|
||||
// DateTime timestamp = DateTimeOffset.FromUnixTimeMilliseconds(reader.ReadInt64()).DateTime;
|
||||
|
||||
string assemblyName = reader.ReadString();
|
||||
string typeName = reader.ReadString();
|
||||
// string assemblyName = reader.ReadString();
|
||||
// string typeName = reader.ReadString();
|
||||
|
||||
Assembly assembly = Assembly.Load(assemblyName);
|
||||
Type targetType = assembly.GetType(typeName);
|
||||
// Assembly assembly = Assembly.Load(assemblyName);
|
||||
// Type targetType = assembly.GetType(typeName);
|
||||
|
||||
preparedObject.ReConfigure(targetType,timestamp);
|
||||
// preparedObject.ReConfigure(targetType,timestamp);
|
||||
|
||||
int nStoredFields = reader.ReadInt32();
|
||||
// int nStoredFields = reader.ReadInt32();
|
||||
|
||||
for (int n = 0; n < nStoredFields; n++)
|
||||
{
|
||||
string fieldName = reader.ReadString();
|
||||
int nBytes = reader.ReadInt32();
|
||||
byte[] fieldBytes = reader.ReadBytes(nBytes);
|
||||
preparedObject.SetFieldBytes(fieldName, fieldBytes);
|
||||
}
|
||||
// for (int n = 0; n < nStoredFields; n++)
|
||||
// {
|
||||
// string fieldName = reader.ReadString();
|
||||
// int nBytes = reader.ReadInt32();
|
||||
// byte[] fieldBytes = reader.ReadBytes(nBytes);
|
||||
// preparedObject.SetFieldBytes(fieldName, fieldBytes);
|
||||
// }
|
||||
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
// reader.Close();
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
using System;
|
||||
using ln.types.odb.values;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class IgnoreFieldAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
public delegate ODBValue ODBMap(ODBMapper mapper, object value);
|
||||
public delegate object ODBUnmap(ODBMapper mapper, ODBValue oval);
|
||||
public delegate ODBValue ODBMap<T>(ODBMapper mapper, T value);
|
||||
public delegate T ODBUnmap<T>(ODBMapper mapper, ODBValue oval);
|
||||
|
||||
public interface IODBMapping
|
||||
{
|
||||
ODBValue MapValue(ODBMapper mapper, object value);
|
||||
object UnmapValue(ODBMapper mapper, ODBValue oval);
|
||||
}
|
||||
public interface IODBMapping<T>
|
||||
{
|
||||
ODBValue MapValue(ODBMapper mapper, T value);
|
||||
T UnmapValue(ODBMapper mapper, ODBValue oval);
|
||||
}
|
||||
|
||||
public class SimpleMapping : IODBMapping
|
||||
{
|
||||
ODBMap map;
|
||||
ODBUnmap unmap;
|
||||
|
||||
public SimpleMapping(ODBMap map,ODBUnmap unmap)
|
||||
{
|
||||
this.map = map;
|
||||
this.unmap = unmap;
|
||||
}
|
||||
|
||||
public ODBValue MapValue(ODBMapper mapper, object value)
|
||||
{
|
||||
return map(mapper, value);
|
||||
}
|
||||
|
||||
public object UnmapValue(ODBMapper mapper, ODBValue oval)
|
||||
{
|
||||
return unmap(mapper, oval);
|
||||
}
|
||||
}
|
||||
public class SimpleMapping<T> : SimpleMapping
|
||||
{
|
||||
public SimpleMapping(ODBMap<T> map, ODBUnmap<T> unmap)
|
||||
:base((mapper, value) => map(mapper,(T)value),(mapper, oval) => unmap(mapper,oval))
|
||||
{}
|
||||
}
|
||||
|
||||
public class ODBMapper
|
||||
{
|
||||
public static ODBMapper Default { get; } = new ODBMapper();
|
||||
|
||||
Dictionary<Type, IODBMapping> mappings = new Dictionary<Type, IODBMapping>();
|
||||
|
||||
private ODBMapper()
|
||||
{
|
||||
RegisterMapping<string>(
|
||||
(mapper, value) => new ODBStringValue(value),
|
||||
(mapper, oval) => oval.AsString
|
||||
);
|
||||
RegisterMapping<int>(
|
||||
(mapper, value) => new ODBInteger(value),
|
||||
(mapper, oval) => oval.AsInt
|
||||
);
|
||||
RegisterMapping<short>(
|
||||
(mapper, value) => new ODBInteger(value),
|
||||
(mapper, oval) => oval.AsShort
|
||||
);
|
||||
RegisterMapping<byte>(
|
||||
(mapper, value) => new ODBInteger(value),
|
||||
(mapper, oval) => oval.AsByte
|
||||
);
|
||||
|
||||
RegisterMapping<uint>(
|
||||
(mapper, value) => new ODBUInteger(value),
|
||||
(mapper, oval) => oval.AsUInt
|
||||
);
|
||||
RegisterMapping<ushort>(
|
||||
(mapper, value) => new ODBUInteger(value),
|
||||
(mapper, oval) => oval.AsUShort
|
||||
);
|
||||
RegisterMapping<char>(
|
||||
(mapper, value) => new ODBUInteger(value),
|
||||
(mapper, oval) => oval.AsChar
|
||||
);
|
||||
|
||||
RegisterMapping<double>(
|
||||
(mapper, value) => new ODBDouble(value),
|
||||
(mapper, oval) => oval.AsDouble
|
||||
);
|
||||
RegisterMapping<float>(
|
||||
(mapper, value) => new ODBDouble(value),
|
||||
(mapper, oval) => oval.AsFloat
|
||||
);
|
||||
|
||||
RegisterMapping<DateTime>(
|
||||
(mapper, value) => new ODBLong(DateTime.MinValue.Equals(value) ? 0 : new DateTimeOffset(value).ToUnixTimeMilliseconds() ),
|
||||
(mapper, oval) => DateTimeOffset.FromUnixTimeMilliseconds(oval.AsLong).DateTime
|
||||
);
|
||||
RegisterMapping<TimeSpan>(
|
||||
(mapper, value) => new ODBDouble(value.TotalMilliseconds),
|
||||
(mapper, oval) => TimeSpan.FromMilliseconds(oval.AsDouble)
|
||||
);
|
||||
|
||||
RegisterMapping<Guid>(
|
||||
(mapper, value) => new ODBGuid(value),
|
||||
(mapper, oval) => oval.AsGuid
|
||||
);
|
||||
|
||||
RegisterMapping<long>(
|
||||
(mapper, value) => new ODBLong(value),
|
||||
(mapper, oval) => oval.AsLong
|
||||
);
|
||||
RegisterMapping<ulong>(
|
||||
(mapper, value) => new ODBULong(value),
|
||||
(mapper, oval) => oval.AsULong
|
||||
);
|
||||
|
||||
RegisterMapping<bool>(
|
||||
(mapper, value) => new ODBInteger(value ? -1 : 0),
|
||||
(mapper, oval) => oval.AsBool
|
||||
);
|
||||
|
||||
RegisterMapping(typeof(object),new ObjectMapping());
|
||||
}
|
||||
|
||||
public void RegisterMapping(Type nativeType,IODBMapping mapping)
|
||||
{
|
||||
mappings[nativeType] = mapping;
|
||||
}
|
||||
public void RegisterMapping(Type nativeType, ODBMap map, ODBUnmap unmap)
|
||||
{
|
||||
mappings[nativeType] = new SimpleMapping(map, unmap);
|
||||
}
|
||||
public void RegisterMapping<T>(ODBMap<T> map, ODBUnmap<T> unmap)
|
||||
{
|
||||
mappings[typeof(T)] = new SimpleMapping<T>(map, unmap);
|
||||
}
|
||||
|
||||
public IODBMapping GetMapping<T>() => null;
|
||||
public IODBMapping GetMapping(Type type)
|
||||
{
|
||||
if (mappings.ContainsKey(type))
|
||||
return mappings[type];
|
||||
|
||||
if (typeof(string).Equals(type))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Dictionary<,>)))
|
||||
{
|
||||
mappings.Add(type, new DictionaryMapping());
|
||||
return mappings[type];
|
||||
}
|
||||
else if (type.GetInterfaces().Contains(typeof(IDictionary)))
|
||||
{
|
||||
mappings.Add(type, new DictionaryMapping());
|
||||
return mappings[type];
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
mappings.Add(type, new ListMapping(type));
|
||||
return mappings[type];
|
||||
}
|
||||
else if (!type.IsPrimitive)
|
||||
{
|
||||
mappings.Add(type, new ClassMapping(type));
|
||||
return mappings[type];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual ODBValue MapValue(object value)
|
||||
{
|
||||
if (value == null)
|
||||
return ODBNull.Instance;
|
||||
|
||||
IODBMapping mapping = GetMapping(value.GetType());
|
||||
if (mapping != null)
|
||||
return mappings[value.GetType()].MapValue(this,value);
|
||||
|
||||
throw new NotSupportedException(String.Format("Can't map {0} ({1})",value.GetType(),value));
|
||||
}
|
||||
public virtual object UnmapValue(Type targetType,ODBValue value)
|
||||
{
|
||||
if (ODBNull.Instance.Equals(value))
|
||||
return null;
|
||||
|
||||
if (value is ODBDocument)
|
||||
{
|
||||
ODBDocument doc = value as ODBDocument;
|
||||
String asmname = doc["__asm__"].AsString;
|
||||
String typename = doc["__type__"].AsString;
|
||||
|
||||
targetType = Assembly.Load(asmname).GetType(typename);
|
||||
}
|
||||
|
||||
IODBMapping mapping = GetMapping(targetType);
|
||||
if (mapping != null)
|
||||
return mappings[targetType].UnmapValue(this,value);
|
||||
|
||||
return Convert.ChangeType(value.Value, targetType);
|
||||
}
|
||||
public virtual T ToNativeValue<T>(ODBValue value)
|
||||
{
|
||||
return (T)UnmapValue(typeof(T), value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -12,26 +12,26 @@ using System.IO;
|
|||
using ln.types.serialize;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class ODBObjectReader : ObjectReader
|
||||
{
|
||||
public ODB ODB { get; }
|
||||
//public class ODBObjectReader : ObjectReader
|
||||
//{
|
||||
// public ODB ODB { get; }
|
||||
|
||||
public ODBObjectReader(ODB odb, Stream stream) :
|
||||
base(stream)
|
||||
{
|
||||
ODB = odb;
|
||||
}
|
||||
// public ODBObjectReader(ODB odb, Stream stream) :
|
||||
// base(stream)
|
||||
// {
|
||||
// ODB = odb;
|
||||
// }
|
||||
|
||||
public override object QueryReferencedObject(object re)
|
||||
{
|
||||
if (re is Guid)
|
||||
{
|
||||
Guid persistenceID = (Guid)re;
|
||||
IPersistent persistent = ODB.LoadPersistent(persistenceID);
|
||||
return persistent;
|
||||
}
|
||||
// public override object QueryReferencedObject(object re)
|
||||
// {
|
||||
// if (re is Guid)
|
||||
// {
|
||||
// Guid persistenceID = (Guid)re;
|
||||
// IPersistent persistent = ODB.LoadPersistent(persistenceID);
|
||||
// return persistent;
|
||||
// }
|
||||
|
||||
return base.QueryReferencedObject(re);
|
||||
}
|
||||
}
|
||||
// return base.QueryReferencedObject(re);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -14,30 +14,30 @@ using ln.types.serialize;
|
|||
using System.Linq;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
class ODBObjectWriter : ObjectWriter
|
||||
{
|
||||
public IPersistent[] ReferencedPersistents => referencedPersistents.Values.ToArray();
|
||||
public Guid[] ReferencedPersistentIDs => referencedPersistents.Keys.ToArray();
|
||||
//class ODBObjectWriter : ObjectWriter
|
||||
//{
|
||||
// public IPersistent[] ReferencedPersistents => referencedPersistents.Values.ToArray();
|
||||
// public Guid[] ReferencedPersistentIDs => referencedPersistents.Keys.ToArray();
|
||||
|
||||
private Dictionary<Guid, IPersistent> referencedPersistents = new Dictionary<Guid, IPersistent>();
|
||||
// private Dictionary<Guid, IPersistent> referencedPersistents = new Dictionary<Guid, IPersistent>();
|
||||
|
||||
public ODBObjectWriter(Stream stream)
|
||||
: base(stream)
|
||||
{}
|
||||
// public ODBObjectWriter(Stream stream)
|
||||
// : base(stream)
|
||||
// {}
|
||||
|
||||
public override object QueryReference(object o)
|
||||
{
|
||||
if (o is IPersistent)
|
||||
{
|
||||
IPersistent persistent = o as IPersistent;
|
||||
Guid persistenceID = persistent.GetPersistenceID();
|
||||
// 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);
|
||||
// if (!referencedPersistents.ContainsKey(persistenceID))
|
||||
// referencedPersistents.Add(persistenceID, persistent);
|
||||
|
||||
return persistenceID;
|
||||
}
|
||||
return base.QueryReference(o);
|
||||
}
|
||||
}
|
||||
// return persistenceID;
|
||||
// }
|
||||
// return base.QueryReference(o);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
// *
|
||||
// **/
|
||||
using System;
|
||||
using LiteDB;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class Persistent : IPersistent
|
||||
{
|
||||
[BsonId]
|
||||
public Guid PersistenceID { get; private set; }
|
||||
|
||||
public Persistent()
|
||||
|
|
|
@ -3,163 +3,163 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class PersistentList<T> : IList<T> where T: IPersistent
|
||||
{
|
||||
private Dictionary<Guid, T> persistentInstances = new Dictionary<Guid, T>();
|
||||
private List<Guid> index = new List<Guid>();
|
||||
//public class PersistentList<T> : IList<T> where T: IPersistent
|
||||
//{
|
||||
// private Dictionary<Guid, T> persistentInstances = new Dictionary<Guid, T>();
|
||||
// private List<Guid> index = new List<Guid>();
|
||||
|
||||
public ODB ODB { get; }
|
||||
// public ODB ODB { get; }
|
||||
|
||||
public PersistentList(ODB odb)
|
||||
{
|
||||
ODB = odb;
|
||||
}
|
||||
// public PersistentList(ODB odb)
|
||||
// {
|
||||
// ODB = odb;
|
||||
// }
|
||||
|
||||
public T this[int n]
|
||||
{
|
||||
get {
|
||||
Guid persistentID = index[n];
|
||||
if (!persistentInstances.ContainsKey(persistentID))
|
||||
persistentInstances[persistentID] = (T)ODB.LoadPersistent(persistentID);
|
||||
// public T this[int n]
|
||||
// {
|
||||
// get {
|
||||
// Guid persistentID = index[n];
|
||||
// if (!persistentInstances.ContainsKey(persistentID))
|
||||
// persistentInstances[persistentID] = (T)ODB.LoadPersistent(persistentID);
|
||||
|
||||
return persistentInstances[persistentID];
|
||||
}
|
||||
set {
|
||||
if (value == null)
|
||||
index[n] = Guid.Empty;
|
||||
// return persistentInstances[persistentID];
|
||||
// }
|
||||
// set {
|
||||
// if (value == null)
|
||||
// index[n] = Guid.Empty;
|
||||
|
||||
Guid persistenceID = value.GetPersistenceID();
|
||||
persistentInstances[persistenceID] = value;
|
||||
index[n] = persistenceID;
|
||||
}
|
||||
}
|
||||
// Guid persistenceID = value.GetPersistenceID();
|
||||
// persistentInstances[persistenceID] = value;
|
||||
// index[n] = persistenceID;
|
||||
// }
|
||||
// }
|
||||
|
||||
public int Count => index.Count;
|
||||
public bool IsReadOnly => false;
|
||||
// public int Count => index.Count;
|
||||
// public bool IsReadOnly => false;
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
index.Add(Guid.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
Guid persistenceID = item.GetPersistenceID();
|
||||
persistentInstances[persistenceID] = item;
|
||||
index.Add(persistenceID);
|
||||
}
|
||||
}
|
||||
// public void Add(T item)
|
||||
// {
|
||||
// if (item == null)
|
||||
// {
|
||||
// index.Add(Guid.Empty);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Guid persistenceID = item.GetPersistenceID();
|
||||
// persistentInstances[persistenceID] = item;
|
||||
// index.Add(persistenceID);
|
||||
// }
|
||||
// }
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
persistentInstances.Clear();
|
||||
index.Clear();
|
||||
}
|
||||
// public void Clear()
|
||||
// {
|
||||
// persistentInstances.Clear();
|
||||
// index.Clear();
|
||||
// }
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
Guid persistenceID = item.GetPersistenceID();
|
||||
if (index.Contains(persistenceID))
|
||||
return true;
|
||||
// public bool Contains(T item)
|
||||
// {
|
||||
// Guid persistenceID = item.GetPersistenceID();
|
||||
// if (index.Contains(persistenceID))
|
||||
// return true;
|
||||
|
||||
foreach (T mine in this)
|
||||
{
|
||||
if (mine.Equals(item))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// foreach (T mine in this)
|
||||
// {
|
||||
// if (mine.Equals(item))
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
foreach (T item in this)
|
||||
{
|
||||
array[arrayIndex] = this[arrayIndex];
|
||||
arrayIndex++;
|
||||
}
|
||||
}
|
||||
// public void CopyTo(T[] array, int arrayIndex)
|
||||
// {
|
||||
// foreach (T item in this)
|
||||
// {
|
||||
// array[arrayIndex] = this[arrayIndex];
|
||||
// arrayIndex++;
|
||||
// }
|
||||
// }
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return new PersistentListEnumerator(this);
|
||||
}
|
||||
// public IEnumerator<T> GetEnumerator()
|
||||
// {
|
||||
// return new PersistentListEnumerator(this);
|
||||
// }
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
|
||||
// public int IndexOf(T item)
|
||||
// {
|
||||
// Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
|
||||
|
||||
int i = index.IndexOf(persistenceID);
|
||||
if (i < 0)
|
||||
{
|
||||
for (int n=0;n<Count;n++)
|
||||
{
|
||||
if (this[n].Equals(item))
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
// int i = index.IndexOf(persistenceID);
|
||||
// if (i < 0)
|
||||
// {
|
||||
// for (int n=0;n<Count;n++)
|
||||
// {
|
||||
// if (this[n].Equals(item))
|
||||
// return n;
|
||||
// }
|
||||
// }
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
public void Insert(int _index, T item)
|
||||
{
|
||||
Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
|
||||
index.Insert(_index, persistenceID);
|
||||
persistentInstances[persistenceID] = item;
|
||||
}
|
||||
// public void Insert(int _index, T item)
|
||||
// {
|
||||
// Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
|
||||
// index.Insert(_index, persistenceID);
|
||||
// persistentInstances[persistenceID] = item;
|
||||
// }
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
int ind = IndexOf(item);
|
||||
if (ind >= 0)
|
||||
RemoveAt(ind);
|
||||
// public bool Remove(T item)
|
||||
// {
|
||||
// int ind = IndexOf(item);
|
||||
// if (ind >= 0)
|
||||
// RemoveAt(ind);
|
||||
|
||||
return ind >= 0;
|
||||
}
|
||||
// return ind >= 0;
|
||||
// }
|
||||
|
||||
public void RemoveAt(int _index)
|
||||
{
|
||||
Guid persistenceID = index[_index];
|
||||
if (persistentInstances.ContainsKey(persistenceID))
|
||||
persistentInstances.Remove(persistenceID);
|
||||
index.RemoveAt(_index);
|
||||
}
|
||||
// public void RemoveAt(int _index)
|
||||
// {
|
||||
// Guid persistenceID = index[_index];
|
||||
// if (persistentInstances.ContainsKey(persistenceID))
|
||||
// persistentInstances.Remove(persistenceID);
|
||||
// index.RemoveAt(_index);
|
||||
// }
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return new PersistentListEnumerator(this);
|
||||
}
|
||||
// IEnumerator IEnumerable.GetEnumerator()
|
||||
// {
|
||||
// return new PersistentListEnumerator(this);
|
||||
// }
|
||||
|
||||
class PersistentListEnumerator : IEnumerator<T>
|
||||
{
|
||||
int currentIndex = -1;
|
||||
PersistentList<T> persistentList;
|
||||
// class PersistentListEnumerator : IEnumerator<T>
|
||||
// {
|
||||
// int currentIndex = -1;
|
||||
// PersistentList<T> persistentList;
|
||||
|
||||
|
||||
public PersistentListEnumerator(PersistentList<T> persistentList)
|
||||
{
|
||||
this.persistentList = persistentList;
|
||||
}
|
||||
// public PersistentListEnumerator(PersistentList<T> persistentList)
|
||||
// {
|
||||
// this.persistentList = persistentList;
|
||||
// }
|
||||
|
||||
public T Current => persistentList[currentIndex];
|
||||
object IEnumerator.Current => persistentList[currentIndex];
|
||||
// public T Current => persistentList[currentIndex];
|
||||
// object IEnumerator.Current => persistentList[currentIndex];
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
persistentList = null;
|
||||
}
|
||||
// public void Dispose()
|
||||
// {
|
||||
// persistentList = null;
|
||||
// }
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
currentIndex++;
|
||||
return (currentIndex < persistentList.Count);
|
||||
}
|
||||
// public bool MoveNext()
|
||||
// {
|
||||
// currentIndex++;
|
||||
// return (currentIndex < persistentList.Count);
|
||||
// }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
currentIndex = -1;
|
||||
}
|
||||
}
|
||||
// public void Reset()
|
||||
// {
|
||||
// currentIndex = -1;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -13,171 +13,169 @@ using System.CodeDom;
|
|||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ln.types.sync;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public class PreparedObject
|
||||
{
|
||||
public ODB ODB { get; private set; }
|
||||
//public class PreparedObject
|
||||
//{
|
||||
// public ODB ODB { get; private set; }
|
||||
|
||||
public DateTime Timestamp { get; private set; }
|
||||
public Type PreparedType { get; private set; }
|
||||
// public DateTime Timestamp { get; private set; }
|
||||
// public Type PreparedType { get; private set; }
|
||||
|
||||
public IPersistent Instance { get; set; }
|
||||
public Guid PersistenceID { get; private set; }
|
||||
// public IPersistent Instance { get; set; }
|
||||
// public Guid PersistenceID { get; private set; }
|
||||
|
||||
public string[] StoredFieldNames => fieldStore.Keys.ToArray();
|
||||
// public string[] StoredFieldNames => fieldStore.Keys.ToArray();
|
||||
|
||||
public IEnumerable<Guid> ReferencedPersistentIDs => referencedPersistentIDs;
|
||||
public IEnumerable<IPersistent> ReferencedPersistents => referencedPersistents;
|
||||
// public IEnumerable<Guid> ReferencedPersistentIDs => referencedPersistentIDs;
|
||||
// public IEnumerable<IPersistent> ReferencedPersistents => referencedPersistents;
|
||||
|
||||
List<Guid> referencedPersistentIDs = new List<Guid>();
|
||||
HashSet<IPersistent> referencedPersistents = new HashSet<IPersistent>();
|
||||
Dictionary<string, byte[]> fieldStore = new Dictionary<string, byte[]>();
|
||||
// List<Guid> referencedPersistentIDs = new List<Guid>();
|
||||
// HashSet<IPersistent> referencedPersistents = new HashSet<IPersistent>();
|
||||
// Dictionary<string, byte[]> fieldStore = new Dictionary<string, byte[]>();
|
||||
|
||||
public PreparedObject(ODB odb,Type preparedType,Guid persistenceID)
|
||||
{
|
||||
ODB = odb;
|
||||
Timestamp = DateTime.Now;
|
||||
PreparedType = preparedType;
|
||||
PersistenceID = persistenceID;
|
||||
Instance = null;
|
||||
}
|
||||
public PreparedObject(ODB odb, IPersistent o)
|
||||
{
|
||||
ODB = odb;
|
||||
Timestamp = DateTime.Now;
|
||||
PreparedType = o.GetType();
|
||||
PersistenceID = o.GetPersistenceID();
|
||||
Instance = o;
|
||||
// public PreparedObject(ODB odb,Type preparedType,Guid persistenceID)
|
||||
// {
|
||||
// ODB = odb;
|
||||
// Timestamp = DateTime.Now;
|
||||
// PreparedType = preparedType;
|
||||
// PersistenceID = persistenceID;
|
||||
// Instance = null;
|
||||
// }
|
||||
// public PreparedObject(ODB odb, IPersistent o)
|
||||
// {
|
||||
// ODB = odb;
|
||||
// Timestamp = DateTime.Now;
|
||||
// PreparedType = o.GetType();
|
||||
// PersistenceID = o.GetPersistenceID();
|
||||
// Instance = o;
|
||||
|
||||
SyncFromInstance();
|
||||
}
|
||||
// SyncFromInstance();
|
||||
// }
|
||||
|
||||
private IEnumerable<FieldInfo> GetAllFields(Type type)
|
||||
{
|
||||
if (type == typeof(object))
|
||||
{
|
||||
return new FieldInfo[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetAllFields(type.BaseType).Concat(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly));
|
||||
}
|
||||
}
|
||||
// private IEnumerable<FieldInfo> GetAllFields(Type type)
|
||||
// {
|
||||
// if (type == typeof(object))
|
||||
// {
|
||||
// return new FieldInfo[0];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return GetAllFields(type.BaseType).Concat(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly));
|
||||
// }
|
||||
// }
|
||||
|
||||
private void SyncFromInstance()
|
||||
{
|
||||
referencedPersistentIDs.Clear();
|
||||
FieldInfo[] fields = GetAllFields(PreparedType).ToArray();
|
||||
// public void SyncFromInstance()
|
||||
// {
|
||||
// referencedPersistentIDs.Clear();
|
||||
// FieldInfo[] fields = GetAllFields(PreparedType).ToArray();
|
||||
|
||||
foreach (FieldInfo fieldInfo in fields)
|
||||
{
|
||||
if (!fieldInfo.IsStatic)
|
||||
{
|
||||
object value = fieldInfo.GetValue(Instance);
|
||||
if (value == null)
|
||||
{
|
||||
fieldStore[fieldInfo.Name] = new byte[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryStream objectStream = new MemoryStream();
|
||||
ODBObjectWriter objectWriter = new ODBObjectWriter(objectStream);
|
||||
// foreach (FieldInfo fieldInfo in fields)
|
||||
// {
|
||||
// if (!fieldInfo.IsStatic && (fieldInfo.GetCustomAttribute<Unsynced>() == null))
|
||||
// {
|
||||
// object value = fieldInfo.GetValue(Instance);
|
||||
// if (value == null)
|
||||
// {
|
||||
// fieldStore[fieldInfo.Name] = new byte[0];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// MemoryStream objectStream = new MemoryStream();
|
||||
// ODBObjectWriter objectWriter = new ODBObjectWriter(objectStream);
|
||||
|
||||
objectWriter.Write(value);
|
||||
// objectWriter.Write(value);
|
||||
|
||||
fieldStore[fieldInfo.Name] = objectStream.ToArray();
|
||||
referencedPersistentIDs.AddRange(objectWriter.ReferencedPersistentIDs);
|
||||
foreach (IPersistent persistent in objectWriter.ReferencedPersistents)
|
||||
referencedPersistents.Add(persistent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void SyncToInstance()
|
||||
{
|
||||
foreach (FieldInfo fieldInfo in GetAllFields(PreparedType))
|
||||
{
|
||||
if (!fieldInfo.IsStatic)
|
||||
{
|
||||
byte[] bytes = fieldStore[fieldInfo.Name];
|
||||
if (bytes.Length == 0)
|
||||
{
|
||||
fieldInfo.SetValue(Instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryStream objectStream = new MemoryStream(fieldStore[fieldInfo.Name]);
|
||||
ODBObjectReader objectReader = new ODBObjectReader(ODB, objectStream);
|
||||
// fieldStore[fieldInfo.Name] = objectStream.ToArray();
|
||||
// referencedPersistentIDs.AddRange(objectWriter.ReferencedPersistentIDs);
|
||||
// foreach (IPersistent persistent in objectWriter.ReferencedPersistents)
|
||||
// referencedPersistents.Add(persistent);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// public void SyncToInstance()
|
||||
// {
|
||||
// foreach (FieldInfo fieldInfo in GetAllFields(PreparedType))
|
||||
// {
|
||||
// if (!fieldInfo.IsStatic && (fieldInfo.GetCustomAttribute<Unsynced>() == null))
|
||||
// {
|
||||
// byte[] bytes = fieldStore[fieldInfo.Name];
|
||||
// if (bytes.Length == 0)
|
||||
// {
|
||||
// fieldInfo.SetValue(Instance, null);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// MemoryStream objectStream = new MemoryStream(fieldStore[fieldInfo.Name]);
|
||||
// ODBObjectReader objectReader = new ODBObjectReader(ODB, objectStream);
|
||||
|
||||
object value = objectReader.Read();
|
||||
fieldInfo.SetValue(Instance, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// object value = objectReader.Read();
|
||||
// fieldInfo.SetValue(Instance, value);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
public void ReConfigure(Type targetType,DateTime timestamp)
|
||||
{
|
||||
Timestamp = timestamp;
|
||||
PreparedType = targetType;
|
||||
fieldStore.Clear();
|
||||
Instance = null;
|
||||
}
|
||||
// public void ReConfigure(Type targetType,DateTime timestamp)
|
||||
// {
|
||||
// Timestamp = timestamp;
|
||||
// PreparedType = targetType;
|
||||
// fieldStore.Clear();
|
||||
// Instance = null;
|
||||
// }
|
||||
|
||||
public byte[] GetFieldBytes(string fieldName)
|
||||
{
|
||||
return fieldStore[fieldName];
|
||||
}
|
||||
public void SetFieldBytes(string fieldName,byte[] bytes)
|
||||
{
|
||||
fieldStore[fieldName] = bytes;
|
||||
}
|
||||
// public byte[] GetFieldBytes(string fieldName)
|
||||
// {
|
||||
// return fieldStore[fieldName];
|
||||
// }
|
||||
// public void SetFieldBytes(string fieldName,byte[] bytes)
|
||||
// {
|
||||
// fieldStore[fieldName] = bytes;
|
||||
// }
|
||||
|
||||
public IPersistent CreateInstance()
|
||||
{
|
||||
Instance = (IPersistent)Activator.CreateInstance(PreparedType,true);
|
||||
SyncToInstance();
|
||||
return Instance;
|
||||
}
|
||||
// public IPersistent CreateInstance()
|
||||
// {
|
||||
// Instance = (IPersistent)Activator.CreateInstance(PreparedType,true);
|
||||
// SyncToInstance();
|
||||
// return Instance;
|
||||
// }
|
||||
|
||||
public bool InstanceEquals(PreparedObject other)
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
// public bool InstanceEquals(PreparedObject other)
|
||||
// {
|
||||
// if (other == null)
|
||||
// return false;
|
||||
|
||||
if (Equals(other))
|
||||
{
|
||||
foreach (String fieldName in fieldStore.Keys)
|
||||
{
|
||||
byte[] me = fieldStore[fieldName];
|
||||
byte[] you = other.fieldStore[fieldName];
|
||||
// if (Equals(other))
|
||||
// {
|
||||
// foreach (String fieldName in fieldStore.Keys)
|
||||
// {
|
||||
// byte[] me = fieldStore[fieldName];
|
||||
// byte[] you = other.fieldStore[fieldName];
|
||||
|
||||
File.WriteAllBytes("me.bin", me);
|
||||
File.WriteAllBytes("you.bin", you);
|
||||
// if (!me.AreEqual(you))
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if (!me.AreEqual(you))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// public override int GetHashCode()
|
||||
// {
|
||||
// return PersistenceID.GetHashCode() ^ PreparedType.GetHashCode();
|
||||
// }
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return PersistenceID.GetHashCode() ^ PreparedType.GetHashCode();
|
||||
}
|
||||
// public override bool Equals(object obj)
|
||||
// {
|
||||
// if (obj is PreparedObject)
|
||||
// {
|
||||
// PreparedObject you = obj as PreparedObject;
|
||||
// return PreparedType.Equals(you.PreparedType) && PersistenceID.Equals(you.PersistenceID);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is PreparedObject)
|
||||
{
|
||||
PreparedObject you = obj as PreparedObject;
|
||||
return PreparedType.Equals(you.PreparedType) && PersistenceID.Equals(you.PersistenceID);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
using System;
|
||||
namespace ln.types.odb
|
||||
{
|
||||
public abstract class Storage
|
||||
{
|
||||
public Storage()
|
||||
{
|
||||
}
|
||||
//public abstract class Storage
|
||||
//{
|
||||
// public Storage()
|
||||
// {
|
||||
// }
|
||||
|
||||
|
||||
public abstract bool Contains(Guid persistenceID);
|
||||
// public abstract bool Contains(Guid persistenceID);
|
||||
|
||||
public abstract bool Store(PreparedObject preparedObject);
|
||||
public abstract bool Load(PreparedObject preparedObject);
|
||||
// public abstract bool Store(PreparedObject preparedObject);
|
||||
// public abstract bool Load(PreparedObject preparedObject);
|
||||
|
||||
|
||||
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
namespace ln.types.odb.values
|
||||
{
|
||||
public class ODBDouble : ODBValue
|
||||
{
|
||||
public ODBDouble()
|
||||
:base(0x18)
|
||||
{
|
||||
}
|
||||
public ODBDouble(double value)
|
||||
: this()
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override byte[] ToStorage()
|
||||
{
|
||||
return BitConverter.GetBytes(AsDouble);
|
||||
}
|
||||
|
||||
static ODBDouble()
|
||||
{
|
||||
RegisterDeserializer(0x0018, (b, o, l) => BitConverter.ToDouble(b, o));
|
||||
//RegisterValueFactory(typeof(double), v => new ODBDouble((double)v));
|
||||
//RegisterValueFactory(typeof(float), v => new ODBDouble((double)v));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
namespace ln.types.odb.values
|
||||
{
|
||||
public class ODBGuid : ODBValue
|
||||
{
|
||||
public ODBGuid()
|
||||
:base(0x03)
|
||||
{
|
||||
Value = Guid.NewGuid();
|
||||
}
|
||||
public ODBGuid(Guid guid)
|
||||
:this()
|
||||
{
|
||||
Value = guid;
|
||||
}
|
||||
|
||||
public override byte[] ToStorage()
|
||||
{
|
||||
return AsGuid.ToByteArray();
|
||||
}
|
||||
|
||||
static Guid FromByteArray(byte[] b,int offset)
|
||||
{
|
||||
byte[] s = new byte[16];
|
||||
Array.Copy(b, offset, s, 0, 16);
|
||||
return new Guid(s);
|
||||
}
|
||||
|
||||
static ODBGuid()
|
||||
{
|
||||
RegisterDeserializer(0x03, (b,o,l) => FromByteArray(b,o));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace ln.types.odb.values
|
||||
{
|
||||
public class ODBInteger : ODBValue
|
||||
{
|
||||
public ODBInteger()
|
||||
: base(0x10)
|
||||
{
|
||||
}
|
||||
public ODBInteger(int i)
|
||||
: this()
|
||||
{
|
||||
Value = i;
|
||||
}
|
||||
|
||||
public override bool AsBool => AsInt != 0;
|
||||
|
||||
public override byte[] ToStorage() => BitConverter.GetBytes(AsInt);
|
||||
|
||||
static ODBInteger()
|
||||
{
|
||||
RegisterDeserializer(0x10, (b, o, l) => BitConverter.ToInt32(b, o));
|
||||
//RegisterValueFactory(typeof(int), v => new ODBInteger((int)v));
|
||||
//RegisterValueFactory(typeof(short), v => new ODBInteger((int)(short)v));
|
||||
//RegisterValueFactory(typeof(byte), v => new ODBInteger((int)(byte)v));
|
||||
}
|
||||
|
||||
}
|
||||
public class ODBUInteger : ODBValue
|
||||
{
|
||||
public ODBUInteger()
|
||||
: base(0x11)
|
||||
{
|
||||
}
|
||||
public ODBUInteger(uint i)
|
||||
: this()
|
||||
{
|
||||
Value = i;
|
||||
}
|
||||
|
||||
public override byte[] ToStorage() => BitConverter.GetBytes(AsUInt);
|
||||
|
||||
static ODBUInteger()
|
||||
{
|
||||
RegisterDeserializer(0x11, (b, o, l) => BitConverter.ToUInt32(b, o));
|
||||
//RegisterValueFactory(typeof(uint), v => new ODBUInteger((uint)v));
|
||||
//RegisterValueFactory(typeof(ushort), v => new ODBUInteger((uint)(ushort)v));
|
||||
//RegisterValueFactory(typeof(char), v => new ODBUInteger((uint)(char)v));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace ln.types.odb.values
|
||||
{
|
||||
public class ODBList : ODBValue
|
||||
{
|
||||
List<ODBValue> items = new List<ODBValue>();
|
||||
|
||||
public ODBList()
|
||||
:base(0x02)
|
||||
{
|
||||
}
|
||||
public ODBList(byte[] bytes,int offset,int length)
|
||||
:this()
|
||||
{
|
||||
MemoryStream stream = new MemoryStream(bytes, offset, length);
|
||||
int nItems = stream.ReadInteger();
|
||||
for (int n = 0; n < nItems; n++)
|
||||
items.Add(ODBValue.Read(stream));
|
||||
}
|
||||
|
||||
public ODBValue this[int i]
|
||||
{
|
||||
get => items[i];
|
||||
set => items[i] = value;
|
||||
}
|
||||
|
||||
public void Add(ODBValue value)
|
||||
{
|
||||
items.Add(value);
|
||||
}
|
||||
public void Remove(ODBValue value)
|
||||
{
|
||||
items.Remove(value);
|
||||
}
|
||||
public void RemoveAt(int i)
|
||||
{
|
||||
items.RemoveAt(i);
|
||||
}
|
||||
|
||||
public int Count => items.Count;
|
||||
|
||||
public override object Value {
|
||||
get
|
||||
{
|
||||
object[] a = new object[items.Count];
|
||||
((IList)items).CopyTo(a, 0);
|
||||
return a;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override byte[] ToStorage()
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
BinaryWriter writer = new BinaryWriter(stream);
|
||||
|
||||
writer.Write(items.Count);
|
||||
|
||||
foreach (ODBValue value in items)
|
||||
value.Store(writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
static ODBList()
|
||||
{
|
||||
RegisterDeserializer(0x02, (b, o, l) => new ODBList(b,o,l));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace ln.types.odb.values
|
||||
{
|
||||
public class ODBLong : ODBValue
|
||||
{
|
||||
public ODBLong()
|
||||
: base(0x12)
|
||||
{
|
||||
}
|
||||
public ODBLong(long i)
|
||||
: this()
|
||||
{
|
||||
Value = i;
|
||||
}
|
||||
|
||||
public override byte[] ToStorage() => BitConverter.GetBytes(AsLong);
|
||||
|
||||
public override DateTime AsDateTime => DateTimeOffset.FromUnixTimeMilliseconds(AsLong).DateTime;
|
||||
public override TimeSpan AsTimeSpan => TimeSpan.FromMilliseconds(AsDouble);
|
||||
|
||||
|
||||
static ODBLong()
|
||||
{
|
||||
RegisterDeserializer(0x12, (b, o, l) => BitConverter.ToInt64(b, o));
|
||||
//RegisterValueFactory(typeof(long), v => new ODBLong((long)v));
|
||||
//RegisterValueFactory(typeof(DateTime), v => new ODBLong(new DateTimeOffset((DateTime)v).ToUnixTimeMilliseconds()));
|
||||
}
|
||||
|
||||
}
|
||||
public class ODBULong : ODBValue
|
||||
{
|
||||
public ODBULong()
|
||||
: base(0x13)
|
||||
{
|
||||
}
|
||||
public ODBULong(ulong i)
|
||||
: this()
|
||||
{
|
||||
Value = i;
|
||||
}
|
||||
|
||||
public override byte[] ToStorage() => BitConverter.GetBytes(AsULong);
|
||||
|
||||
static ODBULong()
|
||||
{
|
||||
RegisterDeserializer(0x13, (b, o, l) => BitConverter.ToUInt64(b, o));
|
||||
//RegisterValueFactory(typeof(ulong), v => new ODBULong((ulong)v));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
namespace ln.types.odb.values
|
||||
{
|
||||
|
||||
public class ODBNull : ODBValue
|
||||
{
|
||||
public static readonly ODBNull Instance = new ODBNull();
|
||||
|
||||
public ODBNull()
|
||||
: base(0x00)
|
||||
{ }
|
||||
|
||||
public override byte[] ToStorage()
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
static ODBNull()
|
||||
{
|
||||
RegisterDeserializer(0x00, (b,o,l) => Instance);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj == null) || (obj is ODBNull);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
namespace ln.types.odb.values
|
||||
{
|
||||
public class ODBStringValue : ODBValue
|
||||
{
|
||||
public ODBStringValue()
|
||||
: base(0x01)
|
||||
{ }
|
||||
|
||||
public ODBStringValue(String text)
|
||||
: this()
|
||||
{
|
||||
Value = text;
|
||||
}
|
||||
|
||||
public override byte[] ToStorage()
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(AsString);
|
||||
}
|
||||
|
||||
|
||||
public static implicit operator ODBStringValue(String text)
|
||||
{
|
||||
return new ODBStringValue(text);
|
||||
}
|
||||
|
||||
|
||||
static ODBStringValue()
|
||||
{
|
||||
RegisterDeserializer(0x01, (b, o, l) => new ODBStringValue(Encoding.UTF8.GetString(b, o, l)));
|
||||
// RegisterValueFactory(typeof(string), v => new ODBStringValue((string)v));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
/**
|
||||
* typeCode list
|
||||
*
|
||||
* 0x0000 ODBNull
|
||||
* 0x0001 ODBStringValue
|
||||
* 0x0002 ODBList
|
||||
* 0x0003 ODBGuid
|
||||
*
|
||||
* 0x0010 ODBInteger
|
||||
* 0x0011 ODBUInteger
|
||||
* 0x0012 ODBLong
|
||||
* 0x0013 ODBULong
|
||||
*
|
||||
* 0x0018 ODBDouble
|
||||
*
|
||||
* 0x1000 ODBDocument
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
|
||||
namespace ln.types.odb.values
|
||||
{
|
||||
public delegate ODBValue ODBValueFactory(object value);
|
||||
public delegate ODBValue ODBDeserialize(byte[] storageBytes, int offset, int length);
|
||||
|
||||
public abstract class ODBValue
|
||||
{
|
||||
int storageTypeCode;
|
||||
|
||||
public virtual object Value { get; protected set; }
|
||||
|
||||
protected ODBValue(int storageTypeCode)
|
||||
{
|
||||
this.storageTypeCode = storageTypeCode;
|
||||
}
|
||||
|
||||
protected ODBValue(int storageTypeCode, object value)
|
||||
: this(storageTypeCode)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public abstract byte[] ToStorage();
|
||||
|
||||
public object AsObject => Value;
|
||||
|
||||
public virtual string AsString => (string)Value;
|
||||
|
||||
public virtual bool AsBool => (bool)Value;
|
||||
public virtual byte AsByte => (byte)Value;
|
||||
public virtual char AsChar => (char)Value;
|
||||
public virtual short AsShort => (short)Value;
|
||||
public virtual int AsInt => (int)Value;
|
||||
public virtual long AsLong => (long)Value;
|
||||
public virtual ushort AsUShort => (ushort)Value;
|
||||
public virtual uint AsUInt => (uint)Value;
|
||||
public virtual ulong AsULong => (ulong)Value;
|
||||
|
||||
public virtual double AsDouble => (double)Value;
|
||||
public virtual float AsFloat => (float)Value;
|
||||
|
||||
public virtual Guid AsGuid => (Guid)Value;
|
||||
public virtual DateTime AsDateTime => (DateTime)Value;
|
||||
public virtual TimeSpan AsTimeSpan => (TimeSpan)Value;
|
||||
|
||||
public virtual ODBDocument AsDocument => (ODBDocument)this;
|
||||
|
||||
public virtual void Store(BinaryWriter storage)
|
||||
{
|
||||
byte[] storageBytes = ToStorage();
|
||||
|
||||
storage.Write(storageTypeCode);
|
||||
storage.Write(storageBytes.Length);
|
||||
storage.Write(storageBytes, 0, storageBytes.Length);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Value.GetHashCode();
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is ODBValue)
|
||||
{
|
||||
ODBValue you = obj as ODBValue;
|
||||
return Value.Equals(you.Value);
|
||||
}
|
||||
return Value.Equals(obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//static Dictionary<Type, ODBValueFactory> valueFactories = new Dictionary<Type, ODBValueFactory>();
|
||||
//public static void RegisterValueFactory(Type type, ODBValueFactory factory)
|
||||
//{
|
||||
// valueFactories.Add(type, factory);
|
||||
//}
|
||||
|
||||
public static implicit operator ODBValue(ValueType v)
|
||||
{
|
||||
return ODBMapper.Default.MapValue(v);
|
||||
}
|
||||
public static implicit operator ODBValue(String v)
|
||||
{
|
||||
return ODBMapper.Default.MapValue(v);
|
||||
}
|
||||
|
||||
public static ODBValue FromNative(object v)
|
||||
{
|
||||
return ODBMapper.Default.MapValue(v);
|
||||
}
|
||||
|
||||
static Dictionary<int, ODBDeserialize> valueDeserializers = new Dictionary<int, ODBDeserialize>();
|
||||
public static void RegisterDeserializer(int storageTypeCode, ODBDeserialize deserialize)
|
||||
{
|
||||
valueDeserializers.Add(storageTypeCode, deserialize);
|
||||
}
|
||||
|
||||
public static ODBValue Deserialize(byte[] buffer, ref int offset)
|
||||
{
|
||||
int storageTypeCode = BitConverter.ToInt32(buffer, offset);
|
||||
int storageLength = BitConverter.ToInt32(buffer, offset + 4);
|
||||
ODBValue value = valueDeserializers[storageTypeCode](buffer, offset + 8, storageLength);
|
||||
offset += 8 + storageLength;
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ODBValue Read(Stream stream)
|
||||
{
|
||||
int storageTypeCode = stream.ReadInteger();
|
||||
int storageLength = stream.ReadInteger();
|
||||
byte[] b = new byte[storageLength];
|
||||
stream.Read(b, 0, storageLength);
|
||||
|
||||
return valueDeserializers[storageTypeCode](b, 0, storageLength);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("[ODBValue Value={0}]", Value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Castle.Core" version="4.3.1" targetFramework="net47" />
|
||||
<package id="LiteDB" version="4.1.4" targetFramework="net47" />
|
||||
<package id="Newtonsoft.Json" version="12.0.1" targetFramework="net47" />
|
||||
</packages>
|
|
@ -182,6 +182,7 @@ namespace ln.types.serialize
|
|||
public object ReadObject()
|
||||
{
|
||||
Type type = Read<Type>();
|
||||
|
||||
object o = Activator.CreateInstance(type,true);
|
||||
|
||||
referencedObjects.Add(o);
|
||||
|
|
|
@ -214,33 +214,38 @@ namespace ln.types.threads
|
|||
{
|
||||
supervisorThread = Thread.CurrentThread;
|
||||
|
||||
while (CurrentPoolSize > 0)
|
||||
lock (supervisorThread)
|
||||
{
|
||||
while (CurrentPoolSize != TargetPoolSize)
|
||||
{
|
||||
if (CurrentPoolSize - TargetPoolSize > 0)
|
||||
{
|
||||
lock (queuedJobs)
|
||||
{
|
||||
releaseThreads = CurrentPoolSize - TargetPoolSize;
|
||||
}
|
||||
|
||||
while (CurrentPoolSize > 0)
|
||||
{
|
||||
Monitor.Wait(supervisorThread, 1000);
|
||||
|
||||
while (CurrentPoolSize != TargetPoolSize)
|
||||
{
|
||||
if (CurrentPoolSize - TargetPoolSize > 0)
|
||||
{
|
||||
lock (queuedJobs)
|
||||
{
|
||||
Monitor.PulseAll(queuedJobs);
|
||||
releaseThreads = CurrentPoolSize - TargetPoolSize;
|
||||
}
|
||||
|
||||
if (CurrentPoolSize - TargetPoolSize > 0)
|
||||
{
|
||||
lock (queuedJobs)
|
||||
{
|
||||
Monitor.PulseAll(queuedJobs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CurrentPoolSize - TargetPoolSize < 0)
|
||||
{
|
||||
for (int n = CurrentPoolSize; n < TargetPoolSize; n++)
|
||||
new PoolThread(this);
|
||||
else if (CurrentPoolSize - TargetPoolSize < 0)
|
||||
{
|
||||
for (int n = CurrentPoolSize; n < TargetPoolSize; n++)
|
||||
new PoolThread(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
supervisorThread = null;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue