commit 731c3d5f82934911c3e74074020b992ddb6f8394 Author: Harald Wolff Date: Tue Jan 7 08:48:45 2020 +0100 Initial Commit 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()); + } + } +}