whatever
This commit is contained in:
parent
3bc0641c99
commit
d21c8c9f6d
@ -10,6 +10,7 @@ using Mocha.Core;
|
||||
using Mocha.Core.UI.Server;
|
||||
using Mocha.Core.Logging;
|
||||
using Mocha.Core.Logging.Loggers;
|
||||
using Mocha.Core.Storage;
|
||||
|
||||
/// <summary>
|
||||
/// Provides the entry point for a simple application which starts a Web server
|
||||
@ -56,6 +57,19 @@ public class Program : WebApplication
|
||||
Console.Error.WriteLine("oms: error: failed to write PID file; graceful control will be unavailable");
|
||||
}
|
||||
|
||||
string mdtfile = "/etc/mocha/oms/20250708.mdt";
|
||||
mdtfile = Path.Combine(new string[] { System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "mocha", DateTime.Now.ToString("yyyyMMddHHmmss") + ".mdt" });
|
||||
|
||||
string? workdir = Path.GetDirectoryName(mdtfile);
|
||||
if (workdir != null)
|
||||
{
|
||||
if (!Directory.Exists(workdir))
|
||||
{
|
||||
Directory.CreateDirectory(workdir);
|
||||
}
|
||||
}
|
||||
Oms.Storages.Add(new BinaryOmsStorage(mdtfile));
|
||||
|
||||
DefaultFileLogger logger = new DefaultFileLogger();
|
||||
ConsoleLogger logger2 = new ConsoleLogger();
|
||||
Log.Loggers.Add(logger);
|
||||
@ -122,6 +136,8 @@ public class Program : WebApplication
|
||||
|
||||
UpdateMochafile();
|
||||
|
||||
Oms.ReloadStorages();
|
||||
|
||||
// now we can start the Web server
|
||||
base.OnStartup(e);
|
||||
}
|
||||
|
||||
@ -149,6 +149,11 @@ public class ElementCommand : InstanceCommand
|
||||
// POST http://localhost:4436/tenants/super/instances/2997$1/element
|
||||
// relatedInstance=4170$1
|
||||
|
||||
if (oms.TryParseInstanceRef(context.Request.Form["relatedInstance"], out InstanceHandle h))
|
||||
{
|
||||
omsContext.TargetInstance = h;
|
||||
}
|
||||
|
||||
Response r = oms.ProcessElement(omsContext, elem, context.Request.Form);
|
||||
JsonObject obj = r.GetResponse(oms, omsContext);
|
||||
|
||||
|
||||
@ -55,11 +55,14 @@ namespace Mocha.Core
|
||||
public static Guid ExtractSingleInstanceStringComponent { get; } = new Guid("{FCECCE4E-8D05-485A-AE34-B1B45E766661}");
|
||||
public static Guid InstanceAttributeStringComponent { get; } = new Guid("{623565D5-5AEE-49ED-A5A9-0CFE670507BC}");
|
||||
|
||||
|
||||
public static Guid Prompt { get; } = new Guid("{EC889225-416A-4F73-B8D1-2A42B37AF43E}");
|
||||
/*
|
||||
public static Guid TextPrompt { get; } = new Guid("{195DDDD7-0B74-4498-BF61-B0549FE05CF3}");
|
||||
public static Guid ChoicePrompt { get; } = new Guid("{5597AEEB-922D-48AF-AE67-DF7D951C71DB}");
|
||||
public static Guid InstancePrompt { get; } = new Guid("{F3ECBF1E-E732-4370-BE05-8FA7CC520F50}");
|
||||
public static Guid BooleanPrompt { get; } = new Guid("{a7b49c03-c9ce-4a79-a4b2-e94fc8cd8b29}");
|
||||
*/
|
||||
|
||||
public static Guid Method { get; } = new Guid("{D2813913-80B6-4DD6-9AD6-56D989169734}");
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
namespace Mocha.Core;
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json.Nodes;
|
||||
@ -44,8 +45,12 @@ public abstract class Oms
|
||||
|
||||
public bool ValidateConstraints { get; protected set; } = true;
|
||||
|
||||
public OmsStorage.OmsStorageCollection Storages { get; }
|
||||
|
||||
public Oms()
|
||||
{
|
||||
Storages = new OmsStorage.OmsStorageCollection(this);
|
||||
|
||||
MethodImplementation[] methodImplementations = MBS.Core.Reflection.TypeLoader.GetAvailableTypes<MethodImplementation>(new System.Reflection.Assembly[] { Assembly.GetExecutingAssembly() });
|
||||
foreach (MethodImplementation impl in methodImplementations)
|
||||
{
|
||||
@ -328,13 +333,22 @@ public abstract class Oms
|
||||
protected abstract void AssignRelationshipInternal(InstanceHandle source, InstanceHandle relationship, IEnumerable<InstanceHandle> targets, DateTime effectiveDate);
|
||||
public void AssignRelationship(IInstanceReference source, InstanceHandle relationship, IEnumerable<InstanceHandle> targets, DateTime? effectiveDate = null)
|
||||
{
|
||||
DateTime dt = effectiveDate.GetValueOrDefault(DateTime.Now);
|
||||
|
||||
ValidateConstraintsForRelationship(source.GetHandle(), relationship, targets);
|
||||
AssignRelationshipInternal(source.GetHandle(), relationship, targets, effectiveDate.GetValueOrDefault(DateTime.Now));
|
||||
AssignRelationshipInternal(source.GetHandle(), relationship, targets, dt);
|
||||
|
||||
if (!_InhibitStorage)
|
||||
{
|
||||
foreach (OmsStorage sto in Storages)
|
||||
{
|
||||
sto.WriteRelationship(this, source.GetHandle(), relationship, targets, dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void AssignRelationship(IInstanceReference source, Relationship relationship, IEnumerable<InstanceHandle> targets, DateTime? effectiveDate = null)
|
||||
{
|
||||
ValidateConstraintsForRelationship(source.GetHandle(), relationship.GetHandle(), targets);
|
||||
AssignRelationshipInternal(source.GetHandle(), relationship.GetHandle(), targets, effectiveDate.GetValueOrDefault(DateTime.Now));
|
||||
AssignRelationship(source.GetHandle(), relationship.GetHandle(), targets, effectiveDate.GetValueOrDefault(DateTime.Now));
|
||||
}
|
||||
|
||||
public void AssignRelationship(IInstanceReference source, InstanceHandle relationship, IInstanceReference target, DateTime? effectiveDate = null)
|
||||
@ -360,27 +374,75 @@ public abstract class Oms
|
||||
if (!ValidateConstraints)
|
||||
return;
|
||||
|
||||
if (TryGetAttributeValue<bool>(relationship, GetInstance(KnownAttributeGuids.Boolean.Singular), out bool value))
|
||||
// toggle switches for the various constraints
|
||||
bool enforceSingularRelationshipConstraint = true;
|
||||
bool validateSourceAndDestinationClasses = true;
|
||||
|
||||
// this should possibly be moved outside of what's supposed to only be a "validate" routine
|
||||
bool createSiblingRelationship = true;
|
||||
|
||||
if (enforceSingularRelationshipConstraint)
|
||||
{
|
||||
if (value)
|
||||
if (TryGetAttributeValue<bool>(relationship, GetInstance(KnownAttributeGuids.Boolean.Singular), out bool value))
|
||||
{
|
||||
// enforce singular relationship constraint
|
||||
if (targets.Count() > 1)
|
||||
if (value)
|
||||
{
|
||||
throw new InvalidOperationException("Relationship is Singular; must specify no more than one target instance");
|
||||
// enforce singular relationship constraint
|
||||
if (targets.Count() > 1)
|
||||
{
|
||||
throw new InvalidOperationException("Relationship is Singular; must specify no more than one target instance");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstanceHandle siblingRelationship = GetRelatedInstance(relationship, GetInstance(KnownRelationshipGuids.Relationship__has_sibling__Relationship));
|
||||
if (siblingRelationship != InstanceHandle.Empty)
|
||||
if (validateSourceAndDestinationClasses)
|
||||
{
|
||||
DateTime dt = DateTime.Now;
|
||||
foreach (InstanceHandle target in targets)
|
||||
InstanceHandle ihSourceClass = GetRelatedInstance(relationship, GetInstance(KnownRelationshipGuids.Relationship__has_source__Class));
|
||||
InstanceHandle ihDestinationClass = GetRelatedInstance(relationship, GetInstance(KnownRelationshipGuids.Relationship__has_destination__Class));
|
||||
List<InstanceHandle> ignoreClasses = new List<InstanceHandle>();
|
||||
ignoreClasses.Add(GetInstance(KnownInstanceGuids.Classes.Instance));
|
||||
ignoreClasses.Add(GetInstance(KnownInstanceGuids.Classes.ExecutableReturningWorkData));
|
||||
|
||||
if (ihSourceClass != InstanceHandle.Empty)
|
||||
{
|
||||
//* we use AssignRelationshipInternal here because calling the top-level function
|
||||
//* would result in an infinite loop of sibling assignments
|
||||
AssignRelationshipInternal(target, siblingRelationship, new InstanceHandle[] { source }, dt);
|
||||
if (!IsInstanceOf(source, ihSourceClass) && !ignoreClasses.Contains(ihSourceClass))
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Cannot assign relationship source class `{0}` to a type `{1}`", GetInstanceText(GetParentClass(source)), GetInstanceText(ihSourceClass)));
|
||||
}
|
||||
}
|
||||
if (ihDestinationClass != InstanceHandle.Empty)
|
||||
{
|
||||
foreach (InstanceHandle target in targets)
|
||||
{
|
||||
if (!IsInstanceOf(target, ihDestinationClass) && !ignoreClasses.Contains(ihDestinationClass))
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Cannot assign relationship destination class `{0}` to a type `{1}`", GetInstanceText(GetParentClass(target)), GetInstanceText(ihDestinationClass)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (createSiblingRelationship)
|
||||
{
|
||||
InstanceHandle siblingRelationship = GetRelatedInstance(relationship, GetInstance(KnownRelationshipGuids.Relationship__has_sibling__Relationship));
|
||||
if (siblingRelationship != InstanceHandle.Empty)
|
||||
{
|
||||
DateTime dt = DateTime.Now;
|
||||
foreach (InstanceHandle target in targets)
|
||||
{
|
||||
//* we use AssignRelationshipInternal here because calling the top-level function
|
||||
//* would result in an infinite loop of sibling assignments
|
||||
AssignRelationshipInternal(target, siblingRelationship, new InstanceHandle[] { source }, dt);
|
||||
|
||||
//? this also means that we need to manually loop through storages and update the siblings
|
||||
//? if I had a nickel for every time I called AssignRelationshipInternal,... I'd have two nickels
|
||||
if (!_InhibitStorage)
|
||||
{
|
||||
foreach (OmsStorage sto in Storages)
|
||||
{
|
||||
sto.WriteRelationship(this, target, siblingRelationship, new InstanceHandle[] { source }, dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -389,6 +451,13 @@ public abstract class Oms
|
||||
public void ClearRelationship(InstanceHandle source, InstanceHandle relationship)
|
||||
{
|
||||
ClearRelationshipInternal(source, relationship);
|
||||
if (!_InhibitStorage)
|
||||
{
|
||||
foreach (OmsStorage sto in Storages)
|
||||
{
|
||||
sto.ClearRelationship(this, source, relationship, DateTime.Now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract bool TryGetInstanceInternal(Guid globalIdentifier, out InstanceHandle inst);
|
||||
@ -527,12 +596,21 @@ public abstract class Oms
|
||||
}
|
||||
|
||||
InstanceHandle ir = CreateInstance(guid);
|
||||
SetParentClass(ir, ir_class.GetHandle());
|
||||
|
||||
int ct = CountInstances(ir_class.GetHandle());
|
||||
InstanceKey pclass_key = GetInstanceKey(ir_class.GetHandle());
|
||||
InstanceKey new_index = new InstanceKey(pclass_key.InstanceIndex, ct);
|
||||
SetInstanceKey(ir, new_index);
|
||||
|
||||
DateTime dt = DateTime.Now;
|
||||
if (!_InhibitStorage)
|
||||
{
|
||||
foreach (OmsStorage sto in Storages)
|
||||
{
|
||||
sto.CreateInstance(this, ir, ir_class.GetHandle(), dt);
|
||||
}
|
||||
}
|
||||
SetParentClass(ir, ir_class.GetHandle());
|
||||
return ir;
|
||||
}
|
||||
public T CreateInstanceOf<T>(IInstanceReference ir_class, Guid guid) where T : ConcreteInstanceWrapper
|
||||
@ -744,6 +822,7 @@ public abstract class Oms
|
||||
protected abstract void SetAttributeValueInternal(InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate);
|
||||
public void SetAttributeValue(IInstanceReference source, InstanceHandle attribute, object value, DateTime? effectiveDate = null)
|
||||
{
|
||||
DateTime dt = effectiveDate.GetValueOrDefault(DateTime.Now);
|
||||
InstanceHandle sh = source.GetHandle();
|
||||
ValidateConstraintsForAttribute(sh, attribute, value);
|
||||
|
||||
@ -756,7 +835,15 @@ public abstract class Oms
|
||||
_derivedData[sh][attribute] = value;
|
||||
return;
|
||||
}
|
||||
SetAttributeValueInternal(sh, attribute, value, effectiveDate.GetValueOrDefault(DateTime.Now));
|
||||
SetAttributeValueInternal(sh, attribute, value, dt);
|
||||
|
||||
if (!_InhibitStorage)
|
||||
{
|
||||
foreach (OmsStorage sto in Storages)
|
||||
{
|
||||
sto.WriteAttributeValue(this, source.GetHandle(), attribute, value, dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateConstraintsForAttribute(InstanceHandle source, InstanceHandle attribute, object value)
|
||||
@ -2450,4 +2537,15 @@ public abstract class Oms
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private bool _InhibitStorage = false;
|
||||
public void ReloadStorages()
|
||||
{
|
||||
_InhibitStorage = true;
|
||||
foreach (OmsStorage sto in Storages)
|
||||
{
|
||||
sto.Load(this);
|
||||
}
|
||||
_InhibitStorage = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +352,14 @@ public class OmsMethodBuilder
|
||||
{
|
||||
InstanceHandle method = CreateMethodBase(Oms.GetInstance(KnownInstanceGuids.MethodClasses.BuildUIResponseMethod), forClassInstance, verb, name, accessModifier, isStatic);
|
||||
InstanceHandle r_Build_UI_Response_Method__uses__Executable_returning_Element = Oms.GetInstance(KnownRelationshipGuids.Build_UI_Response_Method__uses__Executable_returning_Element);
|
||||
Oms.AssignRelationship(method, r_Build_UI_Response_Method__uses__Executable_returning_Element, usesExecutableReturningElement);
|
||||
if (usesExecutableReturningElement != InstanceHandle.Empty)
|
||||
{
|
||||
Oms.AssignRelationship(method, r_Build_UI_Response_Method__uses__Executable_returning_Element, usesExecutableReturningElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
//? should we throw an exception here?
|
||||
}
|
||||
return new BuildUIResponseMethod(method);
|
||||
}
|
||||
|
||||
|
||||
87
mocha-dotnet/src/lib/Mocha.Core/OmsStorage.cs
Normal file
87
mocha-dotnet/src/lib/Mocha.Core/OmsStorage.cs
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2025 Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// This file is part of Mocha.NET.
|
||||
//
|
||||
// Mocha.NET is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Mocha.NET is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Mocha.Core;
|
||||
|
||||
public abstract class OmsStorage
|
||||
{
|
||||
public class OmsStorageCollection : System.Collections.ObjectModel.Collection<OmsStorage>
|
||||
{
|
||||
private Oms _parent;
|
||||
public OmsStorageCollection(Oms parent)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void CreateInstanceInternal(Oms oms, InstanceHandle source, InstanceHandle parentClass, DateTime effectiveDate);
|
||||
public void CreateInstance(Oms oms, InstanceHandle source, InstanceHandle parentClass, DateTime effectiveDate)
|
||||
{
|
||||
CreateInstanceInternal(oms, source, parentClass, effectiveDate);
|
||||
if (AutoFlush) Flush();
|
||||
}
|
||||
|
||||
protected abstract void WriteAttributeValueInternal(Oms oms, InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate);
|
||||
public void WriteAttributeValue(Oms oms, InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate)
|
||||
{
|
||||
WriteAttributeValueInternal(oms, source, attribute, value, effectiveDate);
|
||||
if (AutoFlush) Flush();
|
||||
}
|
||||
|
||||
protected abstract void WriteRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, IEnumerable<InstanceHandle> targets, DateTime effectiveDate);
|
||||
public void WriteRelationship(Oms oms, InstanceHandle source, InstanceHandle relationship, IEnumerable<InstanceHandle> targets, DateTime effectiveDate)
|
||||
{
|
||||
WriteRelationshipInternal(oms, source, relationship, targets, effectiveDate);
|
||||
if (AutoFlush) Flush();
|
||||
}
|
||||
|
||||
protected abstract void ClearRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, DateTime effectiveDate);
|
||||
public void ClearRelationship(Oms oms, InstanceHandle source, InstanceHandle relationship, DateTime effectiveDate)
|
||||
{
|
||||
ClearRelationshipInternal(oms, source, relationship, effectiveDate);
|
||||
if (AutoFlush) Flush();
|
||||
}
|
||||
|
||||
protected abstract void OpenInternal();
|
||||
public void Open()
|
||||
{
|
||||
OpenInternal();
|
||||
}
|
||||
|
||||
public bool AutoFlush { get; set; } = true;
|
||||
|
||||
protected abstract void FlushInternal();
|
||||
public void Flush()
|
||||
{
|
||||
FlushInternal();
|
||||
}
|
||||
protected abstract void CloseInternal();
|
||||
public void Close()
|
||||
{
|
||||
CloseInternal();
|
||||
}
|
||||
|
||||
protected abstract void LoadInternal(Oms oms);
|
||||
public void Load(Oms oms)
|
||||
{
|
||||
LoadInternal(oms);
|
||||
}
|
||||
}
|
||||
138
mocha-dotnet/src/lib/Mocha.Core/Storage/BinaryOmsStorage.cs
Normal file
138
mocha-dotnet/src/lib/Mocha.Core/Storage/BinaryOmsStorage.cs
Normal file
@ -0,0 +1,138 @@
|
||||
// Copyright (C) 2025 Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// This file is part of Mocha.NET.
|
||||
//
|
||||
// Mocha.NET is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Mocha.NET is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace Mocha.Core.Storage;
|
||||
|
||||
public class BinaryOmsStorage : OmsStorage
|
||||
{
|
||||
public Stream Stream { get; }
|
||||
|
||||
public BinaryWriter Writer { get; }
|
||||
|
||||
public BinaryOmsStorage(string path)
|
||||
{
|
||||
Stream = System.IO.File.Open(path, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
Writer = new BinaryWriter(Stream);
|
||||
|
||||
Open();
|
||||
}
|
||||
public BinaryOmsStorage(Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
Writer = new BinaryWriter(Stream);
|
||||
|
||||
Open();
|
||||
}
|
||||
|
||||
protected override void OpenInternal()
|
||||
{
|
||||
Writer.Write(new char[] { 'M', 'c', 'J', '!' });
|
||||
Writer.Write(1.0f);
|
||||
}
|
||||
|
||||
protected override void CreateInstanceInternal(Oms oms, InstanceHandle source, InstanceHandle parentClass, DateTime effectiveDate)
|
||||
{
|
||||
Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source);
|
||||
Guid classInstanceGuid = oms.GetGlobalIdentifier(parentClass);
|
||||
|
||||
Writer.Write((byte)0xC1);
|
||||
Writer.Write(sourceInstanceGuid.ToByteArray());
|
||||
Writer.Write(classInstanceGuid.ToByteArray());
|
||||
|
||||
InstanceKey ik = oms.GetInstanceKey(source);
|
||||
Writer.Write(ik.ClassIndex);
|
||||
Writer.Write(ik.InstanceIndex);
|
||||
|
||||
Writer.Write(effectiveDate.ToBinary());
|
||||
Writer.Write(DateTime.Now.ToBinary());
|
||||
}
|
||||
|
||||
protected override void WriteAttributeValueInternal(Oms oms, InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate)
|
||||
{
|
||||
Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source);
|
||||
Guid attributeInstanceGuid = oms.GetGlobalIdentifier(attribute);
|
||||
|
||||
Writer.Write((byte)0xA1);
|
||||
Writer.Write(sourceInstanceGuid.ToByteArray());
|
||||
Writer.Write(attributeInstanceGuid.ToByteArray());
|
||||
WriteBinaryValue(Writer, value);
|
||||
|
||||
Writer.Write(effectiveDate.ToBinary());
|
||||
Writer.Write(DateTime.Now.ToBinary());
|
||||
}
|
||||
|
||||
private void WriteBinaryValue(BinaryWriter writer, object value)
|
||||
{
|
||||
if (value is string s)
|
||||
{
|
||||
writer.Write((int)1);
|
||||
writer.Write(s);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WriteRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, IEnumerable<InstanceHandle> targets, DateTime effectiveDate)
|
||||
{
|
||||
Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source);
|
||||
Guid relationshipInstanceGuid = oms.GetGlobalIdentifier(relationship);
|
||||
|
||||
Writer.Write((byte)0xB1);
|
||||
Writer.Write(sourceInstanceGuid.ToByteArray());
|
||||
Writer.Write(relationshipInstanceGuid.ToByteArray());
|
||||
|
||||
Writer.Write((int)targets.Count());
|
||||
foreach (InstanceHandle target in targets)
|
||||
{
|
||||
Writer.Write(oms.GetGlobalIdentifier(target).ToByteArray());
|
||||
}
|
||||
|
||||
Writer.Write(effectiveDate.ToBinary());
|
||||
Writer.Write(DateTime.Now.ToBinary());
|
||||
}
|
||||
|
||||
protected override void ClearRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, DateTime effectiveDate)
|
||||
{
|
||||
Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source);
|
||||
Guid relationshipInstanceGuid = oms.GetGlobalIdentifier(relationship);
|
||||
|
||||
Writer.Write((byte)0xB0);
|
||||
Writer.Write(sourceInstanceGuid.ToByteArray());
|
||||
Writer.Write(relationshipInstanceGuid.ToByteArray());
|
||||
|
||||
Writer.Write(effectiveDate.ToBinary());
|
||||
Writer.Write(DateTime.Now.ToBinary());
|
||||
}
|
||||
|
||||
protected override void FlushInternal()
|
||||
{
|
||||
Writer.Flush();
|
||||
}
|
||||
|
||||
protected override void CloseInternal()
|
||||
{
|
||||
Writer.Flush();
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
protected override void LoadInternal(Oms oms)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
147
mocha-dotnet/src/lib/Mocha.Core/Storage/JsonOmsStorage.cs
Normal file
147
mocha-dotnet/src/lib/Mocha.Core/Storage/JsonOmsStorage.cs
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (C) 2025 Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// This file is part of Mocha.NET.
|
||||
//
|
||||
// Mocha.NET is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Mocha.NET is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Mocha.Core.Oop.Methods;
|
||||
|
||||
namespace Mocha.Core.Storage;
|
||||
|
||||
public class JsonOmsStorage : StreamOmsStorage
|
||||
{
|
||||
public JsonOmsStorage(string path) : base(path) { }
|
||||
public JsonOmsStorage(Stream stream) : base(stream) { }
|
||||
|
||||
private JsonArray PrimaryArray { get; } = new JsonArray();
|
||||
|
||||
protected override void OpenInternal()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateInstanceInternal(Oms oms, InstanceHandle source, InstanceHandle parentClass, DateTime effectiveDate)
|
||||
{
|
||||
Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source);
|
||||
Guid classInstanceGuid = oms.GetGlobalIdentifier(parentClass); // calling oms.GetParentClass(source) here is unreliable
|
||||
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.Add("type", "createInstance");
|
||||
obj.Add("globalIdentifier", sourceInstanceGuid.ToString("B"));
|
||||
obj.Add("parentClassGlobalIdentifier", classInstanceGuid.ToString("B"));
|
||||
obj.Add("iid", oms.GetInstanceKey(source).ToString());
|
||||
obj.Add("edate", effectiveDate);
|
||||
obj.Add("cdate", DateTime.Now);
|
||||
|
||||
PrimaryArray.Add(obj);
|
||||
}
|
||||
|
||||
protected override void WriteAttributeValueInternal(Oms oms, InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate)
|
||||
{
|
||||
Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source);
|
||||
Guid attributeInstanceGuid = oms.GetGlobalIdentifier(attribute);
|
||||
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.Add("type", "assignAttribute");
|
||||
obj.Add("src", sourceInstanceGuid.ToString("B"));
|
||||
obj.Add("att", attributeInstanceGuid.ToString("B"));
|
||||
obj.Add("value", JsonValue.Create(value));
|
||||
obj.Add("edate", effectiveDate);
|
||||
obj.Add("cdate", DateTime.Now);
|
||||
|
||||
PrimaryArray.Add(obj);
|
||||
}
|
||||
|
||||
protected override void WriteRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, IEnumerable<InstanceHandle> targets, DateTime effectiveDate)
|
||||
{
|
||||
Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source);
|
||||
Guid relationshipInstanceGuid = oms.GetGlobalIdentifier(relationship);
|
||||
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.Add("type", "assignRelationship");
|
||||
obj.Add("src", sourceInstanceGuid.ToString("B"));
|
||||
obj.Add("rel", relationshipInstanceGuid.ToString("B"));
|
||||
|
||||
JsonArray ary = new JsonArray();
|
||||
foreach (InstanceHandle target in targets)
|
||||
{
|
||||
ary.Add(oms.GetGlobalIdentifier(target).ToString("B"));
|
||||
}
|
||||
|
||||
obj.Add("tgts", ary);
|
||||
obj.Add("edate", effectiveDate);
|
||||
obj.Add("cdate", DateTime.Now);
|
||||
PrimaryArray.Add(obj);
|
||||
}
|
||||
|
||||
protected override void ClearRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, DateTime effectiveDate)
|
||||
{
|
||||
Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source);
|
||||
Guid relationshipInstanceGuid = oms.GetGlobalIdentifier(relationship);
|
||||
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.Add("type", "clearRelationship");
|
||||
obj.Add("src", sourceInstanceGuid.ToString("B"));
|
||||
obj.Add("rel", relationshipInstanceGuid.ToString("B"));
|
||||
obj.Add("edate", effectiveDate);
|
||||
obj.Add("cdate", DateTime.Now);
|
||||
PrimaryArray.Add(obj);
|
||||
}
|
||||
|
||||
protected override void CloseInternal()
|
||||
{
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.Add("blocks", PrimaryArray);
|
||||
|
||||
StreamWriter sw = new StreamWriter(Stream);
|
||||
sw.Write(obj.ToString());
|
||||
sw.Flush();
|
||||
|
||||
base.CloseInternal();
|
||||
}
|
||||
|
||||
protected override void LoadInternal(Oms oms)
|
||||
{
|
||||
StreamReader sr = new StreamReader(Stream);
|
||||
string text = sr.ReadToEnd();
|
||||
|
||||
JsonObject? obj = (JsonObject?)JsonNode.Parse(text);
|
||||
if (obj != null)
|
||||
{
|
||||
if (obj.ContainsKey("blocks"))
|
||||
{
|
||||
foreach (JsonObject obj2 in obj["blocks"].AsArray())
|
||||
{
|
||||
string type = obj2["type"].AsValue().ToString();
|
||||
if (type == "createInstance")
|
||||
{
|
||||
Guid globalIdentifier = Guid.Parse(obj2["globalIdentifier"].ToString());
|
||||
Guid parentClassGlobalIdentifier = Guid.Parse(obj2["parentClassGlobalIdentifier"].ToString());
|
||||
InstanceKey iid = InstanceKey.Parse(obj2["iid"].ToString());
|
||||
|
||||
InstanceHandle ih = oms.CreateInstanceOf(oms.GetInstance(parentClassGlobalIdentifier), globalIdentifier);
|
||||
oms.SetInstanceKey(ih, iid);
|
||||
}
|
||||
else if (type == "assignAttribute")
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
40
mocha-dotnet/src/lib/Mocha.Core/Storage/StreamOmsStorage.cs
Normal file
40
mocha-dotnet/src/lib/Mocha.Core/Storage/StreamOmsStorage.cs
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2025 Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// This file is part of Mocha.NET.
|
||||
//
|
||||
// Mocha.NET is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Mocha.NET is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
namespace Mocha.Core.Storage;
|
||||
|
||||
public abstract class StreamOmsStorage : OmsStorage
|
||||
{
|
||||
public Stream Stream { get; }
|
||||
|
||||
public StreamOmsStorage(string path) : this(System.IO.File.Open(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { }
|
||||
public StreamOmsStorage(Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
protected override void FlushInternal()
|
||||
{
|
||||
Stream.Flush();
|
||||
}
|
||||
protected override void CloseInternal()
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
}
|
||||
@ -53,12 +53,21 @@ public abstract class OmsTestsBase
|
||||
return oms;
|
||||
}
|
||||
|
||||
public void ReloadOms()
|
||||
{
|
||||
Oms = CreateOms();
|
||||
}
|
||||
|
||||
protected readonly Guid TEST_CLASS_GUID = new Guid("{5821fc28-6411-4339-a7d2-56dc05591501}");
|
||||
protected readonly Guid TEST_CLASS2_GUID = new Guid("{6351ecb7-da5d-4029-ba3a-196a6dc980e9}");
|
||||
protected readonly Guid TEST_CLASS_INST_GUID = new Guid("{12b4bd54-dabd-4074-be50-ffd78115a85a}");
|
||||
protected readonly Guid TEST_ATTR_GUID = new Guid("{e4f314a4-f4b1-4cf1-95d8-7a927fb7c8a0}");
|
||||
protected readonly Guid TEST_ATTR_BOOL_GUID = new Guid("{b8dc887c-9964-4a66-94b1-6dcd00b196dc}");
|
||||
protected readonly Guid TEST_ATTR_NUM_GUID = new Guid("{62d633df-47ef-43b7-a108-b0b47f5212f6}");
|
||||
/// <summary>
|
||||
/// Test Class.has Test Class 2
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected readonly Guid TEST_REL_GUID = new Guid("{969d98bc-95e0-45a9-92e5-d70c62980c0e}");
|
||||
protected readonly Guid TEST_REL2_GUID = new Guid("{235f025a-90a6-43a6-9be1-0b32716eb95a}");
|
||||
protected readonly string TEST_ATTR_VALUE = "The quick brown fox jumps over the lazy dog.";
|
||||
@ -66,7 +75,7 @@ public abstract class OmsTestsBase
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Oms = CreateOms();
|
||||
ReloadOms();
|
||||
|
||||
// create the Test Class
|
||||
InstanceHandle c_Class = Oms.GetInstance(KnownInstanceGuids.Classes.Class);
|
||||
|
||||
@ -74,13 +74,16 @@ public class BasicTests : OmsTestsBase
|
||||
InstanceHandle irTestClass2 = Oms.GetInstance(TEST_CLASS2_GUID);
|
||||
Assert.That(irTestClass2, Is.Not.EqualTo(InstanceHandle.Empty));
|
||||
|
||||
InstanceHandle ihTestClassInstance = Oms.CreateInstanceOf(irTestClass);
|
||||
InstanceHandle ihTestClassInstance2 = Oms.CreateInstanceOf(irTestClass2);
|
||||
|
||||
InstanceHandle irTestRelationship = Oms.GetInstance(TEST_REL_GUID);
|
||||
Assert.That(irTestRelationship, Is.Not.EqualTo(InstanceHandle.Empty));
|
||||
|
||||
Oms.AssignRelationship(irTestClass, irTestRelationship, irTestClass2);
|
||||
Oms.AssignRelationship(ihTestClassInstance, irTestRelationship, ihTestClassInstance2);
|
||||
|
||||
InstanceHandle irRelated = Oms.GetRelatedInstance(irTestClass, irTestRelationship);
|
||||
Assert.That(irRelated, Is.EqualTo(irTestClass2));
|
||||
InstanceHandle irRelated = Oms.GetRelatedInstance(ihTestClassInstance, irTestRelationship);
|
||||
Assert.That(irRelated, Is.EqualTo(ihTestClassInstance2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@ -61,7 +61,7 @@ public class EvaluateBooleanExpressionMethodTests : MethodTestsBase
|
||||
|
||||
EvaluateBooleanExpressionMethod Method__is__Conditional_Select_Attribute_Method = methodBuilder.CreateEvaluateBooleanExpressionMethod(c_Method, "is", "SAC", AccessModifier.Public, false, Oms.GetInstance(KnownAttributeGuids.Boolean.MethodIsOfTypeSpecified), Instance__get__Parent_Class_rsmb.GetHandle(), RelationalOperator.InSelectionList, Oms.GetInstance(KnownInstanceGuids.MethodClasses.ConditionalSelectAttributeMethod));
|
||||
ReturnAttributeMethodBinding Method__is__Conditional_Select_Attribute_Method_ramb = Method__is__Conditional_Select_Attribute_Method.CreateMethodBinding(Oms);
|
||||
|
||||
|
||||
EvaluateBooleanExpressionMethod Method__is__Get_Relationship_Method = methodBuilder.CreateEvaluateBooleanExpressionMethod(c_Method, "is", "GR", AccessModifier.Public, false, Oms.GetInstance(KnownAttributeGuids.Boolean.MethodIsOfTypeSpecified), Instance__get__Parent_Class_rsmb.GetHandle(), RelationalOperator.InSelectionList, Oms.GetInstance(KnownInstanceGuids.MethodClasses.GetRelationshipMethod));
|
||||
ReturnAttributeMethodBinding Method__is__Get_Relationship_Method_ramb = Method__is__Get_Relationship_Method.CreateMethodBinding(Oms);
|
||||
|
||||
|
||||
@ -37,15 +37,15 @@ public class RelationshipTests : OmsTestsBase
|
||||
public void SetUp()
|
||||
{
|
||||
InstanceHandle c_Class = Oms.GetInstance(KnownInstanceGuids.Classes.Class);
|
||||
|
||||
|
||||
c_TestClass = Oms.GetInstance<Class>(TEST_CLASS_GUID);
|
||||
c_TestClass2 = Oms.GetInstance<Class>(TEST_CLASS2_GUID);
|
||||
|
||||
|
||||
c_TestClassInstance = Oms.CreateInstanceOf(c_TestClass);
|
||||
|
||||
|
||||
c_TestClass2Instance1 = Oms.CreateInstanceOf(c_TestClass2);
|
||||
c_TestClass2Instance2 = Oms.CreateInstanceOf(c_TestClass2);
|
||||
|
||||
|
||||
r_Test_Class__has_single__Test_Class_2 = Oms.CreateRelationship(c_TestClass, "has single", c_TestClass2, TEST_REL3_GUID, true, "single for", TEST_REL4_GUID);
|
||||
r_Test_Class_2__single_for__Test_Class = Oms.GetInstance<Relationship>(TEST_REL4_GUID);
|
||||
|
||||
@ -86,4 +86,30 @@ public class RelationshipTests : OmsTestsBase
|
||||
InstanceHandle ir = Oms.GetRelatedInstance(c_TestClass2Instance1, r_Test_Class_2__single_for__Test_Class);
|
||||
Assert.That(ir, Is.EqualTo(c_TestClassInstance));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CompatibleRelationshipAssignmentThrowsNothing()
|
||||
{
|
||||
InstanceHandle ihClass = Oms.GetInstance(KnownInstanceGuids.Classes.Class);
|
||||
InstanceHandle ihSubClass = Oms.CreateInstanceOf(Oms.GetInstance(KnownInstanceGuids.Classes.BooleanAttribute));
|
||||
InstanceHandle ihRel = Oms.GetInstance(KnownRelationshipGuids.Class__has__Attribute);
|
||||
|
||||
Assert.That(delegate ()
|
||||
{
|
||||
Oms.AssignRelationship(ihClass, ihRel, ihSubClass);
|
||||
}, Throws.Nothing);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IncompatibleRelationshipAssignmentThrowsException()
|
||||
{
|
||||
InstanceHandle ihClass = Oms.GetInstance(KnownInstanceGuids.Classes.Class);
|
||||
InstanceHandle ihSubClass = Oms.GetInstance(KnownInstanceGuids.Classes.BooleanAttribute);
|
||||
InstanceHandle ihRel = Oms.GetInstance(KnownRelationshipGuids.Class__valid_for__Work_Set);
|
||||
|
||||
Assert.That(delegate ()
|
||||
{
|
||||
Oms.AssignRelationship(ihClass, ihRel, ihSubClass);
|
||||
}, Throws.InvalidOperationException);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
// Copyright (C) 2025 Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// This file is part of Mocha.NET.
|
||||
//
|
||||
// Mocha.NET is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Mocha.NET is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Mocha.Core.Storage;
|
||||
using Mocha.Testing;
|
||||
|
||||
namespace Mocha.Core.Tests.Storage;
|
||||
|
||||
public class JsonStorageTests : OmsTestsBase
|
||||
{
|
||||
[Test(Author = "Michael Becker", Description = "Verifies that the create instance, assign attribute, and assign relationship operations save to and load from storage.")]
|
||||
public void BasicTests()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
JsonOmsStorage json = new JsonOmsStorage(ms);
|
||||
Oms.Storages.Add(json);
|
||||
|
||||
InstanceHandle ihTestClass = Oms.GetInstance(TEST_CLASS_GUID);
|
||||
InstanceHandle ihTestClass2 = Oms.GetInstance(TEST_CLASS2_GUID);
|
||||
InstanceHandle ihRel = Oms.GetInstance(TEST_REL_GUID);
|
||||
|
||||
InstanceHandle test = Oms.CreateInstanceOf(ihTestClass, new Guid("1e9b7101-13dc-4d97-9ae4-570a07bd3545"));
|
||||
InstanceHandle test2 = Oms.CreateInstanceOf(ihTestClass2, new Guid("eea0defa-e93d-4b7e-bbe5-c3d654791335"));
|
||||
|
||||
Oms.SetAttributeValue(test, Oms.GetInstance(KnownAttributeGuids.Text.Name), "PICADILLY");
|
||||
|
||||
// check that it worked
|
||||
string v = Oms.GetAttributeValue<string>(test, Oms.GetInstance(KnownAttributeGuids.Text.Name));
|
||||
Assert.That(v, Is.EqualTo("PICADILLY"));
|
||||
|
||||
Oms.AssignRelationship(test, ihRel, test2);
|
||||
|
||||
json.Close();
|
||||
|
||||
byte[] data = ms.ToArray();
|
||||
System.IO.File.WriteAllBytes("/tmp/test.json", data);
|
||||
|
||||
// reload the OMS from scratch
|
||||
ReloadOms();
|
||||
|
||||
ms = new MemoryStream(data);
|
||||
json = new JsonOmsStorage(ms);
|
||||
|
||||
// don't load the save data yet, check to make sure nothing's changed on the OMS
|
||||
Oms.TryGetInstance(new Guid("1e9b7101-13dc-4d97-9ae4-570a07bd3545"), out test);
|
||||
Assert.That(test, Is.EqualTo(InstanceHandle.Empty));
|
||||
|
||||
// now, load the save data
|
||||
Oms.Storages.Add(json);
|
||||
Oms.ReloadStorages();
|
||||
|
||||
// and see if we have the newly-created instance
|
||||
Oms.TryGetInstance(new Guid("1e9b7101-13dc-4d97-9ae4-570a07bd3545"), out test);
|
||||
Assert.That(test, Is.Not.EqualTo(InstanceHandle.Empty));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user