From 731c3d5f82934911c3e74074020b992ddb6f8394 Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Tue, 7 Jan 2020 08:48:45 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 43 ++++++ EmptyProvider.cs | 39 ++++++ IManagedContainer.cs | 29 +++++ IManagedObject.cs | 16 +++ ManagedConsole.cs | 94 +++++++++++++ ManagedContainerBase.cs | 46 +++++++ ManagedForeign.cs | 36 +++++ ManagedNativeContainer.cs | 90 +++++++++++++ ManagedNativeObject.cs | 74 +++++++++++ ManagedObject.cs | 12 ++ ManagedObjectPropertyDescriptor.cs | 129 ++++++++++++++++++ ManagedObjectProvider.cs | 203 +++++++++++++++++++++++++++++ ManagedProperty.cs | 55 ++++++++ ManagedPropertyAttribute.cs | 31 +++++ ManagedRoot.cs | 55 ++++++++ ManagerTree.cs | 10 ++ NativePropertyDescriptor.cs | 35 +++++ Properties/AssemblyInfo.cs | 26 ++++ PropertyDescriptor.cs | 120 +++++++++++++++++ doc/notes.txt | 70 ++++++++++ ln.manage.csproj | 81 ++++++++++++ ln.manage.sln | 35 +++++ provider/CurrentThreadsProvider.cs | 99 ++++++++++++++ test/LNManageTests.cs | 43 ++++++ 24 files changed, 1471 insertions(+) create mode 100644 .gitignore create mode 100644 EmptyProvider.cs create mode 100644 IManagedContainer.cs create mode 100644 IManagedObject.cs create mode 100644 ManagedConsole.cs create mode 100644 ManagedContainerBase.cs create mode 100644 ManagedForeign.cs create mode 100644 ManagedNativeContainer.cs create mode 100644 ManagedNativeObject.cs create mode 100644 ManagedObject.cs create mode 100644 ManagedObjectPropertyDescriptor.cs create mode 100644 ManagedObjectProvider.cs create mode 100644 ManagedProperty.cs create mode 100644 ManagedPropertyAttribute.cs create mode 100644 ManagedRoot.cs create mode 100644 ManagerTree.cs create mode 100644 NativePropertyDescriptor.cs create mode 100644 Properties/AssemblyInfo.cs create mode 100644 PropertyDescriptor.cs create mode 100644 doc/notes.txt create mode 100644 ln.manage.csproj create mode 100644 ln.manage.sln create mode 100644 provider/CurrentThreadsProvider.cs create mode 100644 test/LNManageTests.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2452a0c --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Autosave files +*~ + +# build +[Oo]bj/ +[Bb]in/ +packages/ +TestResults/ + +# globs +Makefile.in +*.DS_Store +*.sln.cache +*.suo +*.cache +*.pidb +*.userprefs +*.usertasks +config.log +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.user +*.tar.gz +tarballs/ +test-results/ +Thumbs.db +.vs/ + +# Mac bundle stuff +*.dmg +*.app + +# resharper +*_Resharper.* +*.Resharper + +# dotCover +*.dotCover + +ln.logging \ No newline at end of file diff --git a/EmptyProvider.cs b/EmptyProvider.cs new file mode 100644 index 0000000..02d19ee --- /dev/null +++ b/EmptyProvider.cs @@ -0,0 +1,39 @@ +// /** +// * File: EmptyProvider.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.Collections.Generic; +using ln.json; +using ln.types.btree; + +namespace ln.manage +{ + public class EmptyProvider : ManagedObjectProvider + { + public EmptyProvider(String name) + : this(name, null) { } + public EmptyProvider(String name, ManagedObjectProvider container) + : base(null, name, container) + { + } + + public override JSONObject CreateJsonDescriptor() + { + JSONObject descriptor = base.CreateJsonDescriptor(); + descriptor["cosmetic"] = true; + return descriptor; + } + + public override void Disable(object o) => throw new NotSupportedException(); + public override void Enable(object o) => throw new NotSupportedException(); + public override object GetManagedObject(object uniqueIdentifier) => throw new NotSupportedException(); + public override ManagedObjectState GetManagedObjectState(object o) => throw new NotSupportedException(); + public override void RemoveObject(object o) => throw new NotSupportedException(); + } +} diff --git a/IManagedContainer.cs b/IManagedContainer.cs new file mode 100644 index 0000000..8bf48a5 --- /dev/null +++ b/IManagedContainer.cs @@ -0,0 +1,29 @@ +// /** +// * File: IManagedContainer.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.Collections.Generic; +namespace ln.manage +{ + public interface IManagedContainer + { + IManagedContainer Parent { get; } + IEnumerable Children { get; } + + string Name { get; } + IEnumerable PropertyDescriptors { get; } + string IdentityPropertyName { get; } + + IManagedObject[] GetManagedObjects(); + IManagedObject GetManagedObject(object identity); + + IManagedObject CreateManagedObject(); + bool DisposeManagedObject(object identity); + } +} diff --git a/IManagedObject.cs b/IManagedObject.cs new file mode 100644 index 0000000..bcf08c5 --- /dev/null +++ b/IManagedObject.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +namespace ln.manage +{ + public interface IManagedObject + { + IManagedContainer Container { get; } + object Identity { get; } + + object GetValue(string propertyName); + void SetValue(string propertyName, object value); + + bool Enabled { get; set; } + bool Valid { get; } + } +} diff --git a/ManagedConsole.cs b/ManagedConsole.cs new file mode 100644 index 0000000..d446311 --- /dev/null +++ b/ManagedConsole.cs @@ -0,0 +1,94 @@ +// /** +// * File: Console.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +using System.Text; +using ln.types; +using System.Linq; +namespace ln.manage +{ + public class ManagedConsole + { + ManagedRoot ManagedRoot { get; } + + public ManagedConsole(ManagedRoot managedRoot) + { + ManagedRoot = managedRoot; + } + + + public String Export() + { + MemoryStream memoryStream = new MemoryStream(); + Export(memoryStream); + return Encoding.UTF8.GetString(memoryStream.ToArray()); + } + public void Export(Stream stream)=> Export(stream, ManagedRoot); + public void Export(Stream stream, IManagedContainer container) => Export(stream, container, true); + public void Export(Stream stream, IManagedContainer container, bool recurse) + { + string[] containerPath = container.GetContainerPath(); + string containerPathString = string.Join("/", containerPath); + + foreach (IManagedObject managedObject in container.GetManagedObjects()) + { + if (object.Equals(managedObject.Container, container)) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(containerPathString); + stringBuilder.Append(" add"); + foreach (PropertyDescriptor propertyDescriptor in container.PropertyDescriptors) + { + stringBuilder.AppendFormat(" {0}={1}", propertyDescriptor.PropertyName, ValueToText(managedObject.GetValue(propertyDescriptor.PropertyName))); + } + stringBuilder.AppendLine(); + + if (managedObject.Enabled) + { + stringBuilder.AppendFormat("{0} enable {1}", containerPathString, managedObject.Identity.ToString()); + stringBuilder.AppendLine(); + } + + stream.WriteBytes(Encoding.UTF8.GetBytes(stringBuilder.ToString())); + } + } + + if (recurse) + { + foreach (IManagedContainer managedContainer in container.Children) + Export(stream, managedContainer, true); + } + } + + public void Execute(String command) + { + + } + + + + + public static string ValueToText(object value) + { + if (value == null) + return ""; + + Type valueType = value.GetType(); + if (valueType.IsArray) + { + object[] array = (object[])value; + return string.Join(",", array.Select((e) => ValueToText(e))); + } + + return value.ToString(); + } + + } +} diff --git a/ManagedContainerBase.cs b/ManagedContainerBase.cs new file mode 100644 index 0000000..d5e693e --- /dev/null +++ b/ManagedContainerBase.cs @@ -0,0 +1,46 @@ +// /** +// * File: ManagedContainerBase.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.Collections.Generic; + +namespace ln.manage +{ + public abstract class ManagedContainerBase : IManagedContainer + { + IManagedContainer parent; + Dictionary containers = new Dictionary(); + + public ManagedContainerBase(IManagedContainer parent,String name) + { + Name = name; + this.parent = parent; + + if (parent is ManagedContainerBase managedContainerBase) + { + managedContainerBase.AddContainer(this); + } + } + + public string Name { get; } + + public IManagedContainer Parent => parent; + public IEnumerable Children => containers.Values; + + public abstract IEnumerable PropertyDescriptors { get; } + public abstract string IdentityPropertyName { get; } + + public abstract IManagedObject CreateManagedObject(); + public abstract bool DisposeManagedObject(object identity); + public abstract IManagedObject GetManagedObject(object identity); + public abstract IManagedObject[] GetManagedObjects(); + + public void AddContainer(IManagedContainer container) => containers.Add(container.Name, container); + } +} diff --git a/ManagedForeign.cs b/ManagedForeign.cs new file mode 100644 index 0000000..3800458 --- /dev/null +++ b/ManagedForeign.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; + +namespace ln.manage +{ + public class UniqueIdentifierAttribute : Attribute + { + } + + //public class ManagedForeign : ManagedObject + //{ + // public object POCO { get; } + // public new ManagedForeignProvider Provider => base.Provider as ManagedForeignProvider; + + // public override object UniqueID => throw new NotImplementedException(); + // public override IEnumerable> Properties => throw new NotImplementedException(); + + // ManagedObjectState state = ManagedObjectState.INVALID; + // public override ManagedObjectState State => state; + + // public ManagedForeign(ManagedForeignProvider provider, object poco) : base(provider) + // { + // POCO = poco; + // } + // public ManagedForeign(ManagedForeignProvider provider) : base(provider) + // { + // POCO = Activator.CreateInstance(provider.ManagedType); + // } + + // public override void Update(IEnumerable> properties) => Provider.Update(this, properties); + + // public override void Enable() => Provider.Enable(this); + // public override void Disable() => Provider.Disable(this); + // public override void Remove() => Provider.Remove(this); + //} +} diff --git a/ManagedNativeContainer.cs b/ManagedNativeContainer.cs new file mode 100644 index 0000000..3666b89 --- /dev/null +++ b/ManagedNativeContainer.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.ComponentModel; +using System.Security.Cryptography; +using System.Reflection; +namespace ln.manage +{ + public class ManagedNativeContainer : ManagedContainerBase where T:class,IDisposable + { + Type managedType; + Dictionary propertyDescriptors = new Dictionary(); + HashSet> managedNativeObjects = new HashSet>(); + + public ManagedNativeContainer(IManagedContainer parent) :this(parent, typeof(T).Name) { } + public ManagedNativeContainer(IManagedContainer parent,String name) + :base(parent,name) + { + managedType = typeof(T); + + foreach (FieldInfo fieldInfo in managedType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (fieldInfo.IsPublic || fieldInfo.GetCustomAttribute() != null) + { + NativePropertyDescriptor nativePropertyDescriptor = new NativePropertyDescriptor(this, fieldInfo); + propertyDescriptors.Add(nativePropertyDescriptor.PropertyName,nativePropertyDescriptor); + } + } + foreach (PropertyInfo propertyInfo in managedType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (propertyInfo.GetGetMethod().IsPublic || propertyInfo.GetCustomAttribute() != null) + { + NativePropertyDescriptor nativePropertyDescriptor = new NativePropertyDescriptor(this, propertyInfo); + propertyDescriptors.Add(nativePropertyDescriptor.PropertyName, nativePropertyDescriptor); + } + } + + foreach (NativePropertyDescriptor nativePropertyDescriptor in NativePropertyDescriptors) + { + if (nativePropertyDescriptor.Identity) + IdentityDescriptor = nativePropertyDescriptor; + } + + } + public IEnumerable NativePropertyDescriptors => propertyDescriptors.Values; + public NativePropertyDescriptor GetNativePropertyDescriptor(string propertyName) => propertyDescriptors[propertyName]; + public NativePropertyDescriptor IdentityDescriptor { get; } + + public override IEnumerable PropertyDescriptors => propertyDescriptors.Values; + public override string IdentityPropertyName => IdentityDescriptor.PropertyName; + + public override IManagedObject CreateManagedObject() + { + ManagedNativeObject managedNativeObject = new ManagedNativeObject(this); + managedNativeObjects.Add(managedNativeObject); + return managedNativeObject; + } + + public override bool DisposeManagedObject(object identity) => DisposeManagedObject(GetManagedObject(identity)); + public bool DisposeManagedObject(ManagedNativeObject managedNativeObject) + { + if (managedNativeObjects.Contains(managedNativeObject)) + { + managedNativeObject.Enabled = false; + managedNativeObjects.Remove(managedNativeObject); + return true; + } + return false; + } + + public override IManagedObject GetManagedObject(object identity) + { + foreach (ManagedNativeObject managedNativeObject in managedNativeObjects) + { + if (Object.Equals(managedNativeObject.Identity, identity)) + return managedNativeObject; + } + throw new KeyNotFoundException(); + } + + public override IManagedObject[] GetManagedObjects() + { + return managedNativeObjects.Cast().ToArray(); + } + } + + + +} diff --git a/ManagedNativeObject.cs b/ManagedNativeObject.cs new file mode 100644 index 0000000..03eebe9 --- /dev/null +++ b/ManagedNativeObject.cs @@ -0,0 +1,74 @@ +// /** +// * File: ManagedNativeObject.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.Collections.Generic; +namespace ln.manage +{ + public class ManagedNativeObject : IManagedObject where T:class,IDisposable + { + T instance; + Dictionary properties = new Dictionary(); + + public ManagedNativeObject(IManagedContainer container) + { + Container = container; + } + + public IManagedContainer Container { get; } + public object Identity => GetValue(Container.IdentityPropertyName); + + public bool Enabled { + get => instance != null; + set + { + if (value && !Enabled) + { + instance = (T)Activator.CreateInstance(); + Sync(); + } else if (!value && Enabled) + { + instance.Dispose(); + SyncBack(); + instance = null; + } + } + } + + public bool Valid => throw new NotImplementedException(); + + public object GetValue(string propertyName) + { + return (instance != null) ? (Container as ManagedNativeContainer).GetNativePropertyDescriptor(propertyName).GetValue(instance) : properties[propertyName]; + } + + public void SetValue(string propertyName, object value) + { + if (instance != null) + (Container as ManagedNativeContainer).GetNativePropertyDescriptor(propertyName).SetValue(instance, value); + properties[propertyName] = value; + } + + private void Sync() + { + foreach (NativePropertyDescriptor nativePropertyDescriptor in (Container as ManagedNativeContainer).NativePropertyDescriptors) + { + if (properties.ContainsKey(nativePropertyDescriptor.PropertyName)) + nativePropertyDescriptor.SetValue(instance, properties[nativePropertyDescriptor.PropertyName]); + } + } + private void SyncBack() + { + foreach (NativePropertyDescriptor nativePropertyDescriptor in (Container as ManagedNativeContainer).NativePropertyDescriptors) + { + properties[nativePropertyDescriptor.PropertyName] = nativePropertyDescriptor.GetValue(instance); + } + } + } +} diff --git a/ManagedObject.cs b/ManagedObject.cs new file mode 100644 index 0000000..523eba7 --- /dev/null +++ b/ManagedObject.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +namespace ln.manage +{ + public enum ManagedObjectState + { + INVALID = -1, // Object is in invalid state (e.g. invalid property values), implies object being disabled + DISABLED = 0, // Object is disabled + ENABLED = 1 // Object is enabled + } + +} diff --git a/ManagedObjectPropertyDescriptor.cs b/ManagedObjectPropertyDescriptor.cs new file mode 100644 index 0000000..0879811 --- /dev/null +++ b/ManagedObjectPropertyDescriptor.cs @@ -0,0 +1,129 @@ +// /** +// * File: ManagedObjectDescriptor.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.Reflection; +using ln.json; +using ln.types.net; +namespace ln.manage +{ + public class ManagedObjectPropertyDescriptor + { + public ManagedObjectProvider Provider { get; } + public Type ManagedType => Provider.ManagedType; + + public string PropertyName { get; } + public Type PropertyType { get; } + + public bool ReadOnly { get; } + public string LookupPath { get; } + + Action setter; + Func getter; + + public ManagedObjectPropertyDescriptor(ManagedObjectProvider objectProvider, string propertyName, Type propertyType, bool readOnly, string lookupPath, Func getter, Action setter) + { + Provider = objectProvider; + PropertyName = propertyName; + PropertyType = propertyType; + ReadOnly = readOnly; + LookupPath = lookupPath; + + this.getter = getter; + this.setter = setter; + } + public ManagedObjectPropertyDescriptor(ManagedObjectProvider objectProvider,string propertyName,Type propertyType,bool readOnly,string lookupPath) + :this(objectProvider,propertyName,propertyType,readOnly,lookupPath,null,null) + {} + public ManagedObjectPropertyDescriptor(ManagedObjectProvider objectProvider, FieldInfo fieldInfo, string lookupPath) + : this(objectProvider, fieldInfo.Name, fieldInfo.FieldType, fieldInfo.IsInitOnly, lookupPath, fieldInfo.GetValue, fieldInfo.SetValue) + {} + public ManagedObjectPropertyDescriptor(ManagedObjectProvider objectProvider, FieldInfo fieldInfo) + : this(objectProvider, fieldInfo, null) + {} + public ManagedObjectPropertyDescriptor(ManagedObjectProvider objectProvider, PropertyInfo propertyInfo, string lookupPath) + : this(objectProvider, propertyInfo.Name, propertyInfo.PropertyType, !propertyInfo.CanWrite, lookupPath, propertyInfo.GetValue, propertyInfo.SetValue) + {} + public ManagedObjectPropertyDescriptor(ManagedObjectProvider objectProvider, PropertyInfo propertyInfo) + : this(objectProvider, propertyInfo, null) + {} + + public void SetValue(object managedObject, object value) => setter(managedObject, value); + public object GetValue(object managedObject) => getter(managedObject); + + public JSONObject CreateJsonDescriptor() + { + JSONObject descriptor = new JSONObject(); + + descriptor["name"] = PropertyName; + descriptor["readonly"] = ReadOnly; + + if (typeof(string).Equals(PropertyType)) + { + descriptor["type"] = "string"; + } + else if (typeof(int).Equals(PropertyType)) + { + descriptor["type"] = "int"; + } + else if (typeof(double).Equals(PropertyType)) + { + descriptor["type"] = "double"; + } + else if (typeof(IPv4).Equals(PropertyType)) + { + descriptor["type"] = "ip4"; + } + else if (typeof(IPv6).Equals(PropertyType)) + { + descriptor["type"] = "ip6"; + } + else if (typeof(MAC).Equals(PropertyType)) + { + descriptor["type"] = "mac"; + } + else if (PropertyType.IsEnum) + { + if (PropertyType.GetCustomAttribute() != null) + { + JSONObject type = new JSONObject(); + string[] names = Enum.GetNames(PropertyType); + int[] values = (int[])Enum.GetValues(PropertyType); + for (int n = 0; n < names.Length; n++) + type[names[n]] = values[n]; + descriptor["type"] = type; + } + else + { + JSONArray type = new JSONArray(); + string[] symbols = Enum.GetNames(PropertyType); + foreach (string symbol in symbols) + type.Add(symbol); + descriptor["type"] = type; + } + } + else if (LookupPath != null) + { + // ToDo: Implement Referenced Objects + throw new NotImplementedException(); + } + else + { + throw new NotSupportedException(); + } + + + + + return descriptor; + } + + + } +} diff --git a/ManagedObjectProvider.cs b/ManagedObjectProvider.cs new file mode 100644 index 0000000..4e700a7 --- /dev/null +++ b/ManagedObjectProvider.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.ComponentModel; +using System.Security.Cryptography; +using System.Reflection; +using ln.types.btree; +using ln.json; +using ln.logging; +using ln.json.mapping; +namespace ln.manage +{ + public abstract class ManagedObjectProvider + { + public Type ManagedType { get; } + + ManagedObjectProvider container; + public ManagedObjectProvider Container { + get => container; + set { + if (Object.Equals(container, this)) + throw new ArgumentOutOfRangeException(nameof(value)); + + container?.RemoveChildProvider(this); + container = value; + container?.AddChildProvider(this); + + if (!Object.ReferenceEquals(null,container)) + { + List path = new List(); + fillpath(path); + pathlist = PathList.ToArray(); + } + else + { + pathlist = new string[0]; + } + } + } + + public string Name { get; private set; } + + public string[] pathlist = new string[0]; + public string[] PathList => (string[])pathlist.Clone(); + public string Path => String.Join("/", PathList); + + protected MappingBTree propertyDescriptors = new MappingBTree((mopd)=>mopd.PropertyName); + public virtual IEnumerable PropertyDescriptors => propertyDescriptors.Values; + + public String UniqueIdentifierPropertyName { get; protected set; } + + Dictionary children = new Dictionary(); + public IEnumerable Children => children.Values; + + public ManagedObjectProvider(Type type): this(type, type.Name, null) { } + public ManagedObjectProvider(Type type, String name) : this(type, name, null) { } + public ManagedObjectProvider(Type type, String name, ManagedObjectProvider container) : this(true, type, name, container) { } + + protected ManagedObjectProvider(bool buildPropertyDescriptors,Type type,String name,ManagedObjectProvider container) + { + ManagedType = type; + Name = name; + + Container = container; + + if (buildPropertyDescriptors) + BuildPropertyDescriptors(); + } + + private void AddChildProvider(ManagedObjectProvider childProvider) + { + children.Add(childProvider.Name, childProvider); + childProvider.container = this; + } + private void RemoveChildProvider(ManagedObjectProvider childProvider) + { + if (children.TryGetValue(childProvider.Name, out ManagedObjectProvider child) && Object.Equals(child, childProvider)) + { + children.Remove(childProvider.Name); + childProvider.container = null; + } + else + throw new KeyNotFoundException(); + } + + protected virtual void CollectObjects(ISet> set) { CollectLocalObjects(set); CollectChildObjects(set); } + protected virtual void CollectChildObjects(ISet> set) + { + foreach (ManagedObjectProvider childProvider in Children) + { + if (childProvider.ManagedType.IsSubclassOf(ManagedType)) + { + foreach (Tuple childObject in childProvider.EnumerateProviderItems()) + set.Add(childObject); + } + } + } + protected virtual void CollectLocalObjects(ISet> set) { } + + + public virtual IEnumerable EnumerateItems() => EnumerateProviderItems().Select((arg) => arg.Item2); + public virtual IEnumerable> EnumerateProviderItems() + { + HashSet> childObjects = new HashSet>(); + CollectObjects(childObjects); + return childObjects; + } + + public abstract object GetManagedObject(object uniqueIdentifier); + public abstract ManagedObjectState GetManagedObjectState(object o); + + public virtual object CreateManagedObject(IEnumerable> properties) => throw new NotSupportedException(); + public virtual object CreateManagedObject() => CreateManagedObject(null); + + public virtual void ChangeObject(object o, IEnumerable> properties) + { + try + { + foreach (KeyValuePair property in properties) + propertyDescriptors[property.Key].SetValue(o, property.Value); + } + catch (Exception e) + { + Logging.Log(e); + throw e; + } + } + + public abstract void RemoveObject(object o); + public abstract void Enable(object o); + public abstract void Disable(object o); + + private void fillpath(List path) + { + if (Container != null) + Container.fillpath(path); + path.Add(Name); + } + + protected void BuildPropertyDescriptors() + { + if (ManagedType == null) + return; + + foreach (FieldInfo fieldInfo in ManagedType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (fieldInfo.IsPublic || fieldInfo.GetCustomAttribute() != null) + { + propertyDescriptors.Add(new ManagedObjectPropertyDescriptor(this, fieldInfo)); + } + } + foreach (PropertyInfo propertyInfo in ManagedType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (propertyInfo.GetMethod.IsPublic || propertyInfo.GetCustomAttribute() != null) + { + propertyDescriptors.Add(new ManagedObjectPropertyDescriptor(this, propertyInfo)); + } + } + } + + public virtual JSONObject CreateJsonDescriptor() + { + JSONObject descriptor = new JSONObject(); + + descriptor["name"] = Name; + descriptor["readonly"] = false; + descriptor["cosmetic"] = false; + descriptor["hint"] = ""; + descriptor["key"] = UniqueIdentifierPropertyName; + + JSONObject jproperties = new JSONObject(); + foreach (ManagedObjectPropertyDescriptor propertyDescriptor in PropertyDescriptors) + jproperties[propertyDescriptor.PropertyName] = propertyDescriptor.CreateJsonDescriptor(); + descriptor["properties"] = jproperties; + + JSONObject jchildren = new JSONObject(); + foreach (ManagedObjectProvider managedObjectProvider in Children) + jchildren[managedObjectProvider.Name] = managedObjectProvider.CreateJsonDescriptor(); + descriptor["children"] = jchildren; + + return descriptor; + } + + public virtual JSONObject CreateJsonObject(object o) + { + if (!ManagedType.Equals(o.GetType()) && !ManagedType.IsSubclassOf(o.GetType())) + throw new ArgumentException(); + + JSONObject jObject = new JSONObject(); + jObject["provider"] = this.Path; + //jObject["state"] = GetManagedObjectState(o); + + JSONObject jProperties = new JSONObject(); + foreach (ManagedObjectPropertyDescriptor descriptor in PropertyDescriptors) + jProperties[descriptor.PropertyName] = JSONMapper.DefaultMapper.ToJson(descriptor.GetValue(o)); + jObject["properties"] = jProperties; + + return jObject; + } + + } +} diff --git a/ManagedProperty.cs b/ManagedProperty.cs new file mode 100644 index 0000000..8cb2d23 --- /dev/null +++ b/ManagedProperty.cs @@ -0,0 +1,55 @@ +using System; +using System.Reflection; +namespace ln.manage +{ + //public class ManagedProperty + //{ + // public ManagedObjectProvider Provider { get; } + + // public bool ReadOnly { get; } + // public string Name { get; } + // public Type Type { get; } + + // public bool UniqueIdentifier { get; } + + // public string SourcePath { get; } + + // Func getter; + // Action setter; + + // private ManagedProperty(ManagedObjectProvider provider) + // { + // Provider = provider; + // } + // private ManagedProperty(ManagedObjectProvider provider,ManagedPropertyAttribute managedPropertyAttribute) + // { + // if (managedPropertyAttribute.Group == null) + // managedPropertyAttribute.Group = Provider.DefaultName; + + // ReadOnly = managedPropertyAttribute.ReadOnly; + // Name = managedPropertyAttribute.Name; + // SourcePath = managedPropertyAttribute.SourcePath; + // UniqueIdentifier = managedPropertyAttribute.UniqueIdentifier; + // } + // public ManagedProperty(ManagedObjectProvider provider, FieldInfo fieldInfo) + // : this(provider, fieldInfo.GetCustomAttribute() ?? new ManagedPropertyAttribute(fieldInfo)) + // { + // Type = fieldInfo.FieldType; + // getter = fieldInfo.GetValue; + // if (!ReadOnly) + // setter = fieldInfo.SetValue; + // } + // public ManagedProperty(ManagedObjectProvider provider, PropertyInfo propertyInfo) + // :this(provider, propertyInfo.GetCustomAttribute() ?? new ManagedPropertyAttribute(propertyInfo)) + // { + // Type = propertyInfo.PropertyType; + // getter = propertyInfo.GetValue; + // if (!ReadOnly) + // setter = propertyInfo.SetValue; + // } + + // public object GetValue(object managedObject) => getter(managedObject); + // public void SetValue(object managedObject, object v) => setter(managedObject, v); + + //} +} diff --git a/ManagedPropertyAttribute.cs b/ManagedPropertyAttribute.cs new file mode 100644 index 0000000..31e6c22 --- /dev/null +++ b/ManagedPropertyAttribute.cs @@ -0,0 +1,31 @@ +using System; +using System.Reflection; +namespace ln.manage +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class ManagedPropertyAttribute : Attribute + { + public string Group { get; set; } + + public bool ReadOnly { get; set; } + public string Name { get; set; } + + public bool UniqueIdentifier { get; } + + public string SourcePath { get; set; } + + public ManagedPropertyAttribute() + { + } + public ManagedPropertyAttribute(FieldInfo fieldInfo) + { + Name = fieldInfo.Name; + ReadOnly = fieldInfo.IsInitOnly; + } + public ManagedPropertyAttribute(PropertyInfo propertyInfo) + { + Name = propertyInfo.Name; + ReadOnly = !propertyInfo.CanWrite; + } + } +} diff --git a/ManagedRoot.cs b/ManagedRoot.cs new file mode 100644 index 0000000..047b77d --- /dev/null +++ b/ManagedRoot.cs @@ -0,0 +1,55 @@ +// /** +// * File: ManagedRoot.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; +using ln.types; +namespace ln.manage +{ + public class ManagedRoot : ManagedContainerBase + { + public ManagedRoot() + :base(null,"") + { + } + + public override IEnumerable PropertyDescriptors => new PropertyDescriptor[0]; + public override string IdentityPropertyName => throw new NotImplementedException(); + + public override IManagedObject CreateManagedObject() => throw new NotImplementedException(); + public override bool DisposeManagedObject(object identity) => throw new NotImplementedException(); + public override IManagedObject GetManagedObject(object identity) => throw new KeyNotFoundException(); + public override IManagedObject[] GetManagedObjects() => new IManagedObject[0]; + + + + } + static class ManagedContainerExtensions + { + + public static string[] GetContainerPath(this IManagedContainer container) + { + List path = new List(); + Stack stack = new Stack(); + + do + { + stack.Push(container); + container = container.Parent; + } while (container != null); + + while (stack.Count > 0) + path.Add(stack.Pop().Name); + + return path.ToArray(); + } + } +} diff --git a/ManagerTree.cs b/ManagerTree.cs new file mode 100644 index 0000000..60b62aa --- /dev/null +++ b/ManagerTree.cs @@ -0,0 +1,10 @@ +using System; +namespace ln.manage +{ + public class ManagerTree + { + public ManagerTree() + { + } + } +} diff --git a/NativePropertyDescriptor.cs b/NativePropertyDescriptor.cs new file mode 100644 index 0000000..d6bac4f --- /dev/null +++ b/NativePropertyDescriptor.cs @@ -0,0 +1,35 @@ +// /** +// * File: NativePropertyDescriptor.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.Reflection; +using System.ComponentModel; +namespace ln.manage +{ + public class NativePropertyDescriptor : PropertyDescriptor + { + + public Action SetValue { get; } + public Func GetValue { get; } + + public NativePropertyDescriptor(IManagedContainer managedContainer, FieldInfo fieldInfo) + : base(managedContainer, fieldInfo) + { + GetValue = fieldInfo.GetValue; + SetValue = fieldInfo.SetValue; + } + public NativePropertyDescriptor(IManagedContainer managedContainer, PropertyInfo propertyInfo) + : base(managedContainer, propertyInfo) + { + GetValue = propertyInfo.GetValue; + SetValue = propertyInfo.SetValue; + } + + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..02ef1fa --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("ln.manage")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/PropertyDescriptor.cs b/PropertyDescriptor.cs new file mode 100644 index 0000000..3c1a375 --- /dev/null +++ b/PropertyDescriptor.cs @@ -0,0 +1,120 @@ +// /** +// * File: ManagedObjectDescriptor.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.Reflection; +using ln.json; +using ln.types.net; +namespace ln.manage +{ + public class PropertyDescriptorAttribute : Attribute + { + public string Group { get; set; } + public string Alias { get; set; } + public bool ReadOnly { get; set; } + public string LookupPath { get; set; } + + public bool Identity { get; set; } + } + + public class PropertyDescriptor + { + public IManagedContainer Container { get; } + + public string PropertyGroup { get; } + public string PropertyName { get; } + public Type PropertyType { get; } + + public bool ReadOnly { get; } + public string LookupPath { get; } + + public bool Identity { get; } + + public PropertyDescriptor(IManagedContainer container, string propertyGoup, string propertyName, Type propertyType, bool readOnly, string lookupPath, bool identity) + { + Container = container; + PropertyGroup = propertyGoup; + PropertyName = propertyName; + PropertyType = propertyType; + ReadOnly = readOnly; + LookupPath = lookupPath; + Identity = identity; + } + public PropertyDescriptor(IManagedContainer container, FieldInfo fieldInfo) + : this(container, fieldInfo.GetCustomAttribute()?.Group, fieldInfo.GetCustomAttribute()?.Alias ?? fieldInfo.Name, fieldInfo.FieldType, fieldInfo.GetCustomAttribute()?.ReadOnly ?? fieldInfo.IsInitOnly, fieldInfo.GetCustomAttribute()?.LookupPath, fieldInfo.GetCustomAttribute()?.Identity ?? false) + { } + public PropertyDescriptor(IManagedContainer container, PropertyInfo propertyInfo) + : this(container, propertyInfo.GetCustomAttribute()?.Group, propertyInfo.GetCustomAttribute()?.Alias ?? propertyInfo.Name, propertyInfo.PropertyType, propertyInfo.GetCustomAttribute()?.ReadOnly ?? !propertyInfo.CanWrite, propertyInfo.GetCustomAttribute()?.LookupPath, propertyInfo.GetCustomAttribute()?.Identity ?? false) + { } + + public JSONObject CreateJsonDescriptor() + { + JSONObject descriptor = new JSONObject(); + + descriptor["name"] = PropertyName; + descriptor["readonly"] = ReadOnly; + + if (typeof(string).Equals(PropertyType)) + { + descriptor["type"] = "string"; + } + else if (typeof(int).Equals(PropertyType)) + { + descriptor["type"] = "int"; + } + else if (typeof(double).Equals(PropertyType)) + { + descriptor["type"] = "double"; + } + else if (typeof(IPv4).Equals(PropertyType)) + { + descriptor["type"] = "ip4"; + } + else if (typeof(IPv6).Equals(PropertyType)) + { + descriptor["type"] = "ip6"; + } + else if (typeof(MAC).Equals(PropertyType)) + { + descriptor["type"] = "mac"; + } + else if (PropertyType.IsEnum) + { + if (PropertyType.GetCustomAttribute() != null) + { + JSONObject type = new JSONObject(); + string[] names = Enum.GetNames(PropertyType); + int[] values = (int[])Enum.GetValues(PropertyType); + for (int n = 0; n < names.Length; n++) + type[names[n]] = values[n]; + descriptor["type"] = type; + } + else + { + JSONArray type = new JSONArray(); + string[] symbols = Enum.GetNames(PropertyType); + foreach (string symbol in symbols) + type.Add(symbol); + descriptor["type"] = type; + } + } + else if (LookupPath != null) + { + // ToDo: Implement Referenced Objects + throw new NotImplementedException(); + } + else + { + throw new NotSupportedException(); + } + + return descriptor; + } + } +} diff --git a/doc/notes.txt b/doc/notes.txt new file mode 100644 index 0000000..1b95516 --- /dev/null +++ b/doc/notes.txt @@ -0,0 +1,70 @@ + +Notwendige Operationen +---------------------- + +- Deskriptoren lesen +- Objekte listen +- Objekt erstellen +- Objekt ändern +- Objekt entfernen +- Objekt aktivieren +- Objekt deaktivieren + + + +Typen: + +referenz "ref" + +integer "integer" +double "double" +string "string" + +MAC "mac" +IPv4 "ip4" +IPv6 "ip6" + +enum ["VALUE1","VALUE2","VALUE3"] // 1-of-N (Value) + { FLAG1: 1, FLAG2: 2, FLAG3: 16} // M-of-N (Bitmask) + + +PropertyDescriptor +------------------ + +{ + name: "aReferencingProperty", + type: "ref", + readonly: false, + lookup: "/a/path/to/valid/objects", + hint: "You may choose an object from the list of currently active ones", +} +{ + name: "aEnumerationProperty", + type: ["NONE","PRIMARY","SECONDARY"], + readonly: true, + lookup: "/a/path/to/valid/objects", +} + +ObjectDescriptor +---------------- + +{ + name: "someName", // Name of this type + readonly: false, // Objects can be created at this object level + cosmetic: false, // This type is not real but to be used for grouping, menu layout, etc. + hint: "Some text to descripe this object type", + properties: { // Describe all the properties, that are associated with this type + aPropertyName: { ... }, + ... + }, + children: { // ObjectDescriptors for ObjectTypes below this object level + nameOfSomeType: , + ... + }, +} + + + + + + diff --git a/ln.manage.csproj b/ln.manage.csproj new file mode 100644 index 0000000..e89fe54 --- /dev/null +++ b/ln.manage.csproj @@ -0,0 +1,81 @@ + + + + Debug + AnyCPU + {D4E4FD39-6C21-4FCC-8DE0-6494FBE82CEA} + Library + ln.manage + ln.manage + v4.7 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + true + bin\Release + prompt + 4 + false + + + + + nunit + + + + + + + + + + + + + + + + + + + + + + + + + + + {8D9AB9A5-E513-4BA7-A450-534F6456BF28} + ln.types + + + {D9342117-3249-4D8B-87C9-51A50676B158} + ln.json + + + {D471A566-9FB6-41B2-A777-3C32874ECD0E} + ln.logging + + + + + + + + + + + + + \ No newline at end of file diff --git a/ln.manage.sln b/ln.manage.sln new file mode 100644 index 0000000..0cb32e6 --- /dev/null +++ b/ln.manage.sln @@ -0,0 +1,35 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.manage", "ln.manage.csproj", "{D4E4FD39-6C21-4FCC-8DE0-6494FBE82CEA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.json", "..\ln.json\ln.json.csproj", "{D9342117-3249-4D8B-87C9-51A50676B158}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.types", "..\ln.types\ln.types.csproj", "{8D9AB9A5-E513-4BA7-A450-534F6456BF28}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.logging", "..\ln.logging\ln.logging.csproj", "{D471A566-9FB6-41B2-A777-3C32874ECD0E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D4E4FD39-6C21-4FCC-8DE0-6494FBE82CEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4E4FD39-6C21-4FCC-8DE0-6494FBE82CEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4E4FD39-6C21-4FCC-8DE0-6494FBE82CEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4E4FD39-6C21-4FCC-8DE0-6494FBE82CEA}.Release|Any CPU.Build.0 = Release|Any CPU + {D9342117-3249-4D8B-87C9-51A50676B158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9342117-3249-4D8B-87C9-51A50676B158}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9342117-3249-4D8B-87C9-51A50676B158}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9342117-3249-4D8B-87C9-51A50676B158}.Release|Any CPU.Build.0 = Release|Any CPU + {8D9AB9A5-E513-4BA7-A450-534F6456BF28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D9AB9A5-E513-4BA7-A450-534F6456BF28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D9AB9A5-E513-4BA7-A450-534F6456BF28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D9AB9A5-E513-4BA7-A450-534F6456BF28}.Release|Any CPU.Build.0 = Release|Any CPU + {D471A566-9FB6-41B2-A777-3C32874ECD0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D471A566-9FB6-41B2-A777-3C32874ECD0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D471A566-9FB6-41B2-A777-3C32874ECD0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D471A566-9FB6-41B2-A777-3C32874ECD0E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/provider/CurrentThreadsProvider.cs b/provider/CurrentThreadsProvider.cs new file mode 100644 index 0000000..dcc1682 --- /dev/null +++ b/provider/CurrentThreadsProvider.cs @@ -0,0 +1,99 @@ +// /** +// * File: CurrentThreadsProvider.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.Collections.Generic; +using System.Threading; +using System.Diagnostics; + +namespace ln.manage.provider +{ + public class CurrentThreadsProvider : ManagedObjectProvider + { + Dictionary managedThreads = new Dictionary(); + + public CurrentThreadsProvider(ManagedObjectProvider container) + :base(typeof(ManagedThread),"threads",container) + { + } + + public override IEnumerable EnumerateItems() + { + HashSet currentThreads = new HashSet(managedThreads.Values); + + foreach (ProcessThread processThread in Process.GetCurrentProcess().Threads) + { + if (managedThreads.TryGetValue(processThread.Id,out ManagedThread managedThread)) + { + currentThreads.Remove(managedThread); + } else + { + managedThread = new ManagedThread(this, processThread); + managedThreads.Add(managedThread.Id, managedThread); + } + } + + foreach (ManagedThread managedThread in currentThreads) + managedThreads.Remove(managedThread.Id); + + return managedThreads.Values; + } + + public override object GetManagedObject(object uniqueIdentifier) + { + int id = (int)uniqueIdentifier; + if (!managedThreads.ContainsKey(id)) + EnumerateItems(); + return managedThreads[id]; + } + + public override ManagedObjectState GetManagedObjectState(object o) => (o as ManagedThread).State; + + public override void Disable(object o) => throw new NotSupportedException(); + public override void Enable(object o) => throw new NotSupportedException(); + public override void RemoveObject(object o) => throw new NotSupportedException(); + + public class ManagedThread + { + ProcessThread thread; + + public ManagedThread(CurrentThreadsProvider provider,ProcessThread thread) + { + this.thread = thread; + } + + internal ManagedObjectState State + { + get + { + switch (thread.ThreadState) + { + case System.Diagnostics.ThreadState.Running: + case System.Diagnostics.ThreadState.Wait: + return ManagedObjectState.ENABLED; + case System.Diagnostics.ThreadState.Initialized: + case System.Diagnostics.ThreadState.Ready: + case System.Diagnostics.ThreadState.Standby: + case System.Diagnostics.ThreadState.Terminated: + case System.Diagnostics.ThreadState.Transition: + return ManagedObjectState.DISABLED; + default: + return ManagedObjectState.INVALID; + } + } + } + + public int Id => thread.Id; + public int StartAddress => thread.StartAddress.ToInt32(); + public double UserTime => thread.UserProcessorTime.TotalSeconds; + public double TotalTime => thread.TotalProcessorTime.TotalSeconds; + } + } + +} diff --git a/test/LNManageTests.cs b/test/LNManageTests.cs new file mode 100644 index 0000000..03ff15e --- /dev/null +++ b/test/LNManageTests.cs @@ -0,0 +1,43 @@ +using NUnit.Framework; +using System; +using ln.manage.provider; +namespace ln.manage.test +{ + public class Item + { + [UniqueIdentifier] + public string ItemCode { get; set; } + public string ItemName { get; set; } + public string ItemDescription { get; set; } + } + + public class Work : Item + { + public int AccTimePrec { get; set; } + public int AccTimeMin { get; set; } + + public int PricePerTimeUnit { get; set; } + } + + public class Article : Item + { + public int Price { get; set; } + } + + + [TestFixture()] + public class LNManageTests + { + [Test()] + public void TestCase() + { + ManagedObjectProvider pRoot = new EmptyProvider("ManageTest"); + Console.WriteLine("root: {0}", pRoot.CreateJsonDescriptor()); + + ManagedObjectProvider pSystem = new EmptyProvider("System",pRoot); + ManagedObjectProvider pThreads = new CurrentThreadsProvider(pSystem); + + Console.WriteLine("root+work+articles: {0}", pRoot.CreateJsonDescriptor()); + } + } +}