From 7a21f6a9289ca3674beec9373ef4de1ffbc547a7 Mon Sep 17 00:00:00 2001 From: Ahmed Zamil Date: Sat, 15 Feb 2020 11:21:28 +0300 Subject: [PATCH] EntityCore --- Esyur.Stores.EntityCore/EntityResource.cs | 71 ++ Esyur.Stores.EntityCore/EntityStore.cs | 153 ++++ .../Esyur.Stores.EntityCore.csproj | 23 + .../EsyurExtensionOptions.cs | 114 +++ Esyur.Stores.EntityCore/EsyurExtensions.cs | 98 +++ Esyur.Stores.EntityCore/EsyurPlugin.cs | 60 ++ Esyur.Stores.EntityCore/EsyurProxyRewrite.cs | 120 +++ Esyur.Stores.MongoDB/MongoDBStore.cs | 90 ++- Esyur.Stores.MongoDB/MongoDBStoreGeneric.cs | 26 +- Esyur.Stores.MySql/Esyur.Stores.MySql.csproj | 23 - Esyur.Stores.MySql/MySqlStore.cs | 718 ------------------ Esyur.sln | 10 +- Esyur/Data/Codec.cs | 17 + Esyur/Net/HTTP/HTTPServer.cs | 2 +- Esyur/Net/IIP/DistributedConnection.cs | 19 +- .../Net/IIP/DistributedConnectionProtocol.cs | 14 +- Esyur/Net/Sockets/TCPSocket.cs | 2 - Esyur/Proxy/ResourceProxy.cs | 4 +- Esyur/Resource/IResource.cs | 3 +- Esyur/Resource/IStore.cs | 9 + Esyur/Resource/Instance.cs | 88 ++- Esyur/Resource/ResourceAttribute.cs | 42 + Esyur/Resource/Template/AttributeTemplate.cs | 26 + Esyur/Resource/Template/MemberTemplate.cs | 1 + Esyur/Resource/Template/ResourceTemplate.cs | 31 +- Esyur/Resource/Warehouse.cs | 16 +- Esyur/Stores/MemoryStore.cs | 12 +- 27 files changed, 962 insertions(+), 830 deletions(-) create mode 100644 Esyur.Stores.EntityCore/EntityResource.cs create mode 100644 Esyur.Stores.EntityCore/EntityStore.cs create mode 100644 Esyur.Stores.EntityCore/Esyur.Stores.EntityCore.csproj create mode 100644 Esyur.Stores.EntityCore/EsyurExtensionOptions.cs create mode 100644 Esyur.Stores.EntityCore/EsyurExtensions.cs create mode 100644 Esyur.Stores.EntityCore/EsyurPlugin.cs create mode 100644 Esyur.Stores.EntityCore/EsyurProxyRewrite.cs delete mode 100644 Esyur.Stores.MySql/Esyur.Stores.MySql.csproj delete mode 100644 Esyur.Stores.MySql/MySqlStore.cs create mode 100644 Esyur/Resource/ResourceAttribute.cs create mode 100644 Esyur/Resource/Template/AttributeTemplate.cs diff --git a/Esyur.Stores.EntityCore/EntityResource.cs b/Esyur.Stores.EntityCore/EntityResource.cs new file mode 100644 index 0000000..6a26df9 --- /dev/null +++ b/Esyur.Stores.EntityCore/EntityResource.cs @@ -0,0 +1,71 @@ +/* + +Copyright (c) 2020 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Text; +using Esyur.Core; +using Esyur.Resource; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace Esyur.Stores.EntityCore +{ + public class EntityResource : IResource + { + public event DestroyedEvent OnDestroy; + public event PropertyChangedEventHandler PropertyChanged; + + [NotMapped] + public Instance Instance { get; set; } + + public EntityResource() + { + + } + + + protected virtual void Create() + { + + } + + public AsyncReply Trigger(ResourceTrigger trigger) + { + if (trigger == ResourceTrigger.Initialize) + Create(); + + return new AsyncReply(true); + } + + public void Destroy() + { + //throw new NotImplementedException(); + } + + + } +} \ No newline at end of file diff --git a/Esyur.Stores.EntityCore/EntityStore.cs b/Esyur.Stores.EntityCore/EntityStore.cs new file mode 100644 index 0000000..6b0eb82 --- /dev/null +++ b/Esyur.Stores.EntityCore/EntityStore.cs @@ -0,0 +1,153 @@ +/* + +Copyright (c) 2020 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +using Esyur.Core; +using Esyur.Data; +using Esyur.Resource; +using Esyur.Resource.Template; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.EntityFrameworkCore.Proxies; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace Esyur.Stores.EntityCore +{ + public class EntityStore : IStore + { + public Instance Instance { get; set; } + + public event DestroyedEvent OnDestroy; + + /* + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + var extension = optionsBuilder.Options.FindExtension() + ?? new EsyurExtension(); + + + ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); + //optionsBuilder.UseLazyLoadingProxies(); + base.OnConfiguring(optionsBuilder); + } + */ + + /* + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + //modelBuilder.Entity().ToTable("Series"); + //modelBuilder.Entity().ToTable("Episodes").; + //modelBuilder.Ignore + // modelBuilder.Entity(x=>x.Property(p=>p.Instance).HasConversion(v=>v.Managers.) + Console.WriteLine("OnModelCreating"); + //modelBuilder.Entity() + + + base.OnModelCreating(modelBuilder); + }*/ + + + public AsyncReply Get(string path) + { + throw new NotImplementedException(); + } + + public async AsyncReply Put(IResource resource) + { + return true; + } + + public string Link(IResource resource) + { + var p = resource.GetType().GetProperty("Id"); + if (p != null) + return this.Instance.Name + "/" + resource.GetType().Name + "/" + p.GetValue(resource); + else + return this.Instance.Name + "/" + resource.GetType().Name; + } + + public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + return true; + //throw new NotImplementedException(); + } + + public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) + { + return true; + //throw new NotImplementedException(); + } + + public new bool Remove(IResource resource) + { + throw new NotImplementedException(); + } + + public AsyncReply AddChild(IResource parent, IResource child) + { + throw new NotImplementedException(); + } + + public AsyncReply RemoveChild(IResource parent, IResource child) + { + throw new NotImplementedException(); + } + + public AsyncReply AddParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } + + public AsyncReply RemoveParent(IResource child, IResource parent) + { + throw new NotImplementedException(); + } + + public AsyncBag Children(IResource resource, string name) where T : IResource + { + throw new NotImplementedException(); + } + + public AsyncBag Parents(IResource resource, string name) where T : IResource + { + throw new NotImplementedException(); + } + + public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) + { + throw new NotImplementedException(); + } + + public AsyncReply Trigger(ResourceTrigger trigger) + { + return new AsyncReply(true); + } + + public void Destroy() + { + //throw new NotImplementedException(); + } + } +} diff --git a/Esyur.Stores.EntityCore/Esyur.Stores.EntityCore.csproj b/Esyur.Stores.EntityCore/Esyur.Stores.EntityCore.csproj new file mode 100644 index 0000000..68248ce --- /dev/null +++ b/Esyur.Stores.EntityCore/Esyur.Stores.EntityCore.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.0 + Esyur.Stores.EntityCore + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/Esyur.Stores.EntityCore/EsyurExtensionOptions.cs b/Esyur.Stores.EntityCore/EsyurExtensionOptions.cs new file mode 100644 index 0000000..2af074b --- /dev/null +++ b/Esyur.Stores.EntityCore/EsyurExtensionOptions.cs @@ -0,0 +1,114 @@ +/* + +Copyright (c) 2020 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal; +using Microsoft.EntityFrameworkCore.Utilities; +using Microsoft.EntityFrameworkCore.Proxies.Internal; +using System.Linq; + +namespace Esyur.Stores.EntityCore +{ + public class EsyurExtensionOptions : IDbContextOptionsExtension + { + private DbContextOptionsExtensionInfo _info; + EntityStore _store; + + public DbContextOptionsExtensionInfo Info => _info; + + public EntityStore Store => _store; + + public void ApplyServices(IServiceCollection services) + { + services.AddEntityFrameworkProxies(); + + new EntityFrameworkServicesBuilder(services) + .TryAdd(); + } + + public void Validate(IDbContextOptions options) + { + var internalServiceProvider = options.FindExtension()?.InternalServiceProvider; + if (internalServiceProvider != null) + { + var scope = internalServiceProvider.CreateScope(); + var conventionPlugins = scope.ServiceProvider.GetService>(); + if (conventionPlugins?.Any(s => s is EsyurPlugin) == false) + { + throw new InvalidOperationException(""); + } + } + //throw new NotImplementedException(); + } + + public EsyurExtensionOptions(EntityStore store) + { + _info = new ExtensionInfo(this); + _store = store; + } + + + private sealed class ExtensionInfo : DbContextOptionsExtensionInfo + { + private string _logFragment; + + public ExtensionInfo(IDbContextOptionsExtension extension) + : base(extension) + { + } + + private new EsyurExtensionOptions Extension + => (EsyurExtensionOptions)base.Extension; + + public override bool IsDatabaseProvider => false; + + public override string LogFragment => "Esyur"; + + // => _logFragment ??= Extension.UseLazyLoadingProxies && Extension.UseChangeDetectionProxies + // ? "using lazy-loading and change detection proxies " + // : Extension.UseLazyLoadingProxies + // ? "using lazy-loading proxies " + //: Extension.UseChangeDetectionProxies + //? "using change detection proxies " + //: ""; + + public override long GetServiceProviderHashCode() => 2312;//541;//2922;// Extension.UseProxies ? : 0; + + public override void PopulateDebugInfo(IDictionary debugInfo) + { + //debugInfo["Proxies:" + nameof(ProxiesExtensions.UseLazyLoadingProxies)] + // = (Extension._useLazyLoadingProxies ? 541 : 0).ToString(CultureInfo.InvariantCulture); + + //debugInfo["Proxies:" + nameof(ProxiesExtensions.UseChangeDetectionProxies)] + // = (Extension._useChangeDetectionProxies ? 541 : 0).ToString(CultureInfo.InvariantCulture); + } + } + + } +} diff --git a/Esyur.Stores.EntityCore/EsyurExtensions.cs b/Esyur.Stores.EntityCore/EsyurExtensions.cs new file mode 100644 index 0000000..9c59ac6 --- /dev/null +++ b/Esyur.Stores.EntityCore/EsyurExtensions.cs @@ -0,0 +1,98 @@ +/* + +Copyright (c) 2020 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +using Esyur.Resource; +using Esyur.Security.Permissions; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esyur.Stores.EntityCore +{ + public static class EsyurExtensions + { + public static T CreateResource(this DbContext dbContext) where T:IResource + { + return dbContext.GetInfrastructure().CreateResource(); + + } + + public static T CreateResource(this IServiceProvider serviceProvider) where T:IResource + { + var options = serviceProvider.GetService().FindExtension(); + var manager = options.Store.Instance.Managers.Count > 0 ? options.Store.Instance.Managers.First() : null; + + return Warehouse.New("", options.Store, null, manager); + } + + public static DbContextOptionsBuilder UseEsyur(this DbContextOptionsBuilder optionsBuilder, + string name = null, + IResource parent = null, + IPermissionsManager manager = null + + ) + { + var extension = optionsBuilder.Options.FindExtension(); + + if (extension == null) + { + var store = Warehouse.New(name, null, parent, manager); + extension = new EsyurExtensionOptions(store); + } + + ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); + + return optionsBuilder; + + } + + public static DbContextOptionsBuilder UseEsyur( + this DbContextOptionsBuilder optionsBuilder, + string name = null, + IResource parent = null, + IPermissionsManager manager = null) + where TContext : DbContext + { + + + var extension = optionsBuilder.Options.FindExtension(); + + if (extension == null) + { + var store = Warehouse.New(name, null, parent, manager); + extension = new EsyurExtensionOptions(store); + } + + + ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); + + return optionsBuilder; + + } + + } +} diff --git a/Esyur.Stores.EntityCore/EsyurPlugin.cs b/Esyur.Stores.EntityCore/EsyurPlugin.cs new file mode 100644 index 0000000..bc786f4 --- /dev/null +++ b/Esyur.Stores.EntityCore/EsyurPlugin.cs @@ -0,0 +1,60 @@ +/* + +Copyright (c) 2020 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Conventions; +using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; +using Microsoft.EntityFrameworkCore.Proxies.Internal; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esyur.Stores.EntityCore +{ + public class EsyurPlugin : IConventionSetPlugin + { + private readonly IDbContextOptions _options; + private readonly ProviderConventionSetBuilderDependencies _conventionSetBuilderDependencies; + + public EsyurPlugin( + IDbContextOptions options, + ProviderConventionSetBuilderDependencies conventionSetBuilderDependencies) + { + _options = options; + _conventionSetBuilderDependencies = conventionSetBuilderDependencies; + } + + + public ConventionSet ModifyConventions(ConventionSet conventionSet) + { + var extension = _options.FindExtension(); + conventionSet.ModelFinalizedConventions.Add(new EsyurProxyRewrite( + extension, + _conventionSetBuilderDependencies)); + return conventionSet; + + } + } + +} diff --git a/Esyur.Stores.EntityCore/EsyurProxyRewrite.cs b/Esyur.Stores.EntityCore/EsyurProxyRewrite.cs new file mode 100644 index 0000000..5732a74 --- /dev/null +++ b/Esyur.Stores.EntityCore/EsyurProxyRewrite.cs @@ -0,0 +1,120 @@ +/* + +Copyright (c) 2020 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using Esyur.Proxy; +using Esyur.Resource; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Internal; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.Metadata.Conventions; +using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Internal; + +namespace Esyur.Stores.EntityCore +{ + public class EsyurProxyRewrite : IModelFinalizedConvention + { + private static readonly MethodInfo _createInstance + = typeof(EsyurProxyRewrite).GetTypeInfo().GetDeclaredMethod(nameof(EsyurProxyRewrite.CreateInstance)); + + private readonly ConstructorBindingConvention _directBindingConvention; + + public static object CreateInstance( + IDbContextOptions dbContextOptions, + IEntityType entityType, + ILazyLoader loader, + object[] constructorArguments) + { + var options = dbContextOptions.FindExtension(); + + return CreateInstance2( + options, + entityType, + loader, + constructorArguments); + } + + + public static object CreateInstance2( + EsyurExtensionOptions options, + IEntityType entityType, + ILazyLoader loader, + object[] constructorArguments) + { + var manager = options.Store.Instance.Managers.Count > 0 ? options.Store.Instance.Managers.First() : null; + return Warehouse.New(entityType.ClrType, "", options.Store, null, manager); + } + + + + public EsyurProxyRewrite(EsyurExtensionOptions ext, ProviderConventionSetBuilderDependencies conventionSetBuilderDependencies) + { + _directBindingConvention = new ConstructorBindingConvention(conventionSetBuilderDependencies); + + } + + public void ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext context) + { + foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) + { + var proxyType = ResourceProxy.GetProxy(entityType.ClrType); + + var ann = entityType.GetAnnotation(CoreAnnotationNames.ConstructorBinding); + + var binding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding]; + if (binding == null) + _directBindingConvention.ProcessModelFinalized(modelBuilder, context); + + binding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding]; + + + try + + { + entityType.SetAnnotation( + CoreAnnotationNames.ConstructorBinding, + new FactoryMethodBinding( + _createInstance, + new List + { + new DependencyInjectionParameterBinding(typeof(IDbContextOptions), typeof(IDbContextOptions)), + new EntityTypeParameterBinding(), + new DependencyInjectionParameterBinding(typeof(ILazyLoader), typeof(ILazyLoader)), + new ObjectArrayParameterBinding(binding.ParameterBindings) + }, + proxyType)); + } + catch + { + } + + } + } + } +} diff --git a/Esyur.Stores.MongoDB/MongoDBStore.cs b/Esyur.Stores.MongoDB/MongoDBStore.cs index 54d9a31..f00af1d 100644 --- a/Esyur.Stores.MongoDB/MongoDBStore.cs +++ b/Esyur.Stores.MongoDB/MongoDBStore.cs @@ -1,4 +1,28 @@ -using Esyur.Resource; +/* + +Copyright (c) 2017 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +using Esyur.Resource; using System; using Esyur.Core; using MongoDB.Driver.Core; @@ -61,7 +85,7 @@ namespace Esyur.Stores.MongoDB public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime date) { - var objectId = resource.Instance.Attributes["objectId"].ToString(); + var objectId = resource.Instance.Variables["objectId"].ToString(); //var bsonObjectId = new BsonObjectId(new ObjectId(objectId)); var record = this.database.GetCollection("record_" + objectId); @@ -88,7 +112,7 @@ namespace Esyur.Stores.MongoDB [ResourceFunction] public bool Remove(IResource resource) { - var objectId = resource.Instance.Attributes["objectId"].ToString(); + var objectId = resource.Instance.Variables["objectId"].ToString(); var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); this.database.DropCollection("record_" + objectId); @@ -148,8 +172,8 @@ namespace Esyur.Stores.MongoDB // var bag = new AsyncBag(); - resource.Instance.Attributes.Add("children", children.Select(x => x.AsString).ToArray()); - resource.Instance.Attributes.Add("parents", parents.Select(x => x.AsString).ToArray()); + resource.Instance.Variables.Add("children", children.Select(x => x.AsString).ToArray()); + resource.Instance.Variables.Add("parents", parents.Select(x => x.AsString).ToArray()); // Apply store managers foreach (var m in this.Instance.Managers) @@ -275,7 +299,7 @@ namespace Esyur.Stores.MongoDB public string Link(IResource resource) { - return this.Instance.Name + "/id/" + (string)resource.Instance.Attributes["objectId"]; + return this.Instance.Name + "/id/" + (string)resource.Instance.Variables["objectId"]; } public async AsyncReply Put(IResource resource) @@ -285,13 +309,12 @@ namespace Esyur.Stores.MongoDB if (resource == this) return true; - var attrs = resource.Instance.GetAttributes(); foreach (var kv in resources) if (kv.Value.Target == resource) { - resource.Instance.Attributes.Add("objectId", kv.Key); + resource.Instance.Variables.Add("objectId", kv.Key); return true; } @@ -309,7 +332,7 @@ namespace Esyur.Stores.MongoDB }; resourcesCollection.InsertOne(document); - resource.Instance.Attributes["objectId"] = document["_id"].ToString(); + resource.Instance.Variables["objectId"] = document["_id"].ToString(); // now update the document @@ -321,8 +344,8 @@ namespace Esyur.Stores.MongoDB var template = resource.Instance.Template; // setup attributes - resource.Instance.Attributes["children"] = new string[0]; - resource.Instance.Attributes["parents"] = new string[] { this.Instance.Link }; + resource.Instance.Variables["children"] = new string[0]; + resource.Instance.Variables["parents"] = new string[] { this.Instance.Link }; // copy old children (in case we are moving a resource from a store to another. if (resource.Instance.Store != this) @@ -376,7 +399,7 @@ namespace Esyur.Stores.MongoDB resources.Add(document["_id"].AsObjectId.ToString(), new WeakReference(resource)); - //resource.Instance.Attributes["objectId"] = document["_id"].ToString(); + //resource.Instance.Variables["objectId"] = document["_id"].ToString(); ResourceAdded?.Invoke(resource); @@ -390,9 +413,6 @@ namespace Esyur.Stores.MongoDB } } - - - public BsonDocument ComposeStructure(Structure value) { var rt = new BsonDocument { { "type", 1 } }; @@ -435,9 +455,9 @@ namespace Esyur.Stores.MongoDB { rt.Add(new BsonDocument { { "type", 0 }, { "link", r.Instance.Link } }); - //if (r.Instance.Attributes.ContainsKey("objectId")) + //if (r.Instance.Variables.ContainsKey("objectId")) - //rt.Add(new BsonObjectId(new ObjectId((string)r.Instance.Attributes["objectId"]))); + //rt.Add(new BsonObjectId(new ObjectId((string)r.Instance.Variables["objectId"]))); } return rt; @@ -461,7 +481,7 @@ namespace Esyur.Stores.MongoDB return new BsonDocument { { "type", 0 }, { "link", (value as IResource).Instance.Link } }; - //return new BsonObjectId(new ObjectId((string)(value as IResource).Instance.Attributes["objectId"])); + //return new BsonObjectId(new ObjectId((string)(value as IResource).Instance.Variables["objectId"])); case DataType.Structure: return ComposeStructure((Structure)value); @@ -490,15 +510,21 @@ namespace Esyur.Stores.MongoDB throw new NotImplementedException(); } + [ResourceAttribute] + public string Connection { get; set; } + [ResourceAttribute] + public string Collection { get; set; } + [ResourceAttribute] + public string Database { get; set; } public AsyncReply Trigger(ResourceTrigger trigger) { if (trigger == ResourceTrigger.Initialize) { - var collectionName = Instance.Attributes["Collection"] as string ?? "resources"; - var dbName = Instance.Attributes["Database"] as string ?? "Esyur"; - client = new MongoClient(Instance.Attributes["Connection"] as string ?? "mongodb://localhost"); + var collectionName = Collection ?? "resources"; + var dbName = Database ?? "Esyur"; + client = new MongoClient(Connection ?? "mongodb://localhost"); database = client.GetDatabase(dbName); resourcesCollection = this.database.GetCollection(collectionName); @@ -568,7 +594,7 @@ namespace Esyur.Stores.MongoDB //foreach (IResource c in resource.Instance.Children) // children.Add(c.Instance.Link); - var plist = resource.Instance.Attributes["parents"] as string[]; + var plist = resource.Instance.Variables["parents"] as string[]; foreach (var link in plist)// Parents) parents.Add(link); @@ -605,7 +631,7 @@ namespace Esyur.Stores.MongoDB { "attributes", attrsDoc }, { "classname", type.FullName + "," + type.GetTypeInfo().Assembly.GetName().Name }, { "name", resource.Instance.Name }, - { "_id", new BsonObjectId(new ObjectId(resource.Instance.Attributes["objectId"].ToString())) }, + { "_id", new BsonObjectId(new ObjectId(resource.Instance.Variables["objectId"].ToString())) }, {"values", values } }; @@ -627,7 +653,7 @@ namespace Esyur.Stores.MongoDB public AsyncReply GetPropertyRecordByAge(IResource resource, string propertyName, ulong fromAge, ulong toAge) { - var objectId = resource.Instance.Attributes["objectId"].ToString(); + var objectId = resource.Instance.Variables["objectId"].ToString(); var record = this.database.GetCollection("record_" + objectId); var builder = Builders.Filter; @@ -663,7 +689,7 @@ namespace Esyur.Stores.MongoDB public AsyncReply GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate) { - var objectId = resource.Instance.Attributes["objectId"].ToString(); + var objectId = resource.Instance.Variables["objectId"].ToString(); var record = this.database.GetCollection("record_" + objectId); var builder = Builders.Filter; @@ -755,7 +781,7 @@ namespace Esyur.Stores.MongoDB if (resource == this) return true; - var objectId = resource.Instance.Attributes["objectId"].ToString(); + var objectId = resource.Instance.Variables["objectId"].ToString(); var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); var update = Builders.Update @@ -802,7 +828,7 @@ namespace Esyur.Stores.MongoDB } else { - var children = (string[])resource.Instance.Attributes["children"]; + var children = (string[])resource.Instance.Variables["children"]; if (children == null) { @@ -833,7 +859,7 @@ namespace Esyur.Stores.MongoDB } else { - var parents = (string[])resource.Instance.Attributes["parents"]; + var parents = (string[])resource.Instance.Variables["parents"]; if (parents == null) { @@ -862,8 +888,8 @@ namespace Esyur.Stores.MongoDB public AsyncReply AddChild(IResource resource, IResource child) { - var list = (string[])resource.Instance.Attributes["children"]; - resource.Instance.Attributes["children"] = list.Concat(new string[] { child.Instance.Link }).ToArray(); + var list = (string[])resource.Instance.Variables["children"]; + resource.Instance.Variables["children"] = list.Concat(new string[] { child.Instance.Link }).ToArray(); SaveResource(resource); @@ -877,8 +903,8 @@ namespace Esyur.Stores.MongoDB public AsyncReply AddParent(IResource resource, IResource parent) { - var list = (string[])resource.Instance.Attributes["parents"]; - resource.Instance.Attributes["parents"] = list.Concat(new string[] { parent.Instance.Link }).ToArray(); + var list = (string[])resource.Instance.Variables["parents"]; + resource.Instance.Variables["parents"] = list.Concat(new string[] { parent.Instance.Link }).ToArray(); SaveResource(resource); diff --git a/Esyur.Stores.MongoDB/MongoDBStoreGeneric.cs b/Esyur.Stores.MongoDB/MongoDBStoreGeneric.cs index 6f6bab5..e6d078f 100644 --- a/Esyur.Stores.MongoDB/MongoDBStoreGeneric.cs +++ b/Esyur.Stores.MongoDB/MongoDBStoreGeneric.cs @@ -1,4 +1,28 @@ -using Esyur.Core; +/* + +Copyright (c) 2020 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +using Esyur.Core; using Esyur.Data; using Esyur.Proxy; using Esyur.Resource; diff --git a/Esyur.Stores.MySql/Esyur.Stores.MySql.csproj b/Esyur.Stores.MySql/Esyur.Stores.MySql.csproj deleted file mode 100644 index 0608e3f..0000000 --- a/Esyur.Stores.MySql/Esyur.Stores.MySql.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - netstandard2.0 - - - - - - - - - - - - - - - - - - - diff --git a/Esyur.Stores.MySql/MySqlStore.cs b/Esyur.Stores.MySql/MySqlStore.cs deleted file mode 100644 index 0325aa9..0000000 --- a/Esyur.Stores.MySql/MySqlStore.cs +++ /dev/null @@ -1,718 +0,0 @@ -using Esyur.Resource; -using System; -using Esyur.Core; -using Esyur.Data; -using System.Collections.Generic; -using System.Reflection; -using System.Threading.Tasks; -using Esyur.Resource.Template; -using System.Linq; -using Esyur.Security.Permissions; -using Esyur.Proxy; -using MySql.Data.MySqlClient; - -namespace Esyur.Stores.MySql -{ - public class MySqlStore : IStore - { - public Instance Instance { get; set; } - - public event DestroyedEvent OnDestroy; - - string connectionString; - - - Dictionary resources = new Dictionary(); - - - public int Count - { - get { return resources.Count; } - } - - public void Destroy() - { - - - } - - - public bool Record(IResource resource, string propertyName, object value, ulong age, DateTime date) - { - var objectId = resource.Instance.Attributes["objectId"].ToString(); - //var bsonObjectId = new BsonObjectId(new ObjectId(objectId)); - - var record = this.database.GetCollection("record_" + objectId); - - record.InsertOne(new BsonDocument() - { - {"property", propertyName}, {"age", BsonValue.Create(age) }, {"date", date}, {"value", Compose(value) } - }); - - //var col = this.database.GetCollection(collectionName); - - - - var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); - var update = Builders.Update - .Set("values." + propertyName, new BsonDocument { { "age", BsonValue.Create(age) }, - { "modification", date }, - { "value", Compose(value) } }); - resourcesCollection.UpdateOne(filter, update); - - return true; - } - - public bool Remove(IResource resource) - { - var objectId = resource.Instance.Attributes["objectId"].ToString(); - var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); - - this.database.DropCollection("record_" + objectId); - resourcesCollection.DeleteOne(filter); - - return true; - } - - AsyncReply Fetch(string id) - { - - MySqlHelper. - - var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(id))); - var list = resourcesCollection.Find(filter).ToList(); - if (list.Count == 0) - return new AsyncReply(null); - var document = list[0]; - - var type = Type.GetType(document["classname"].AsString); - - if (type == null) - return new AsyncReply(null); - - IResource resource = (IResource)Activator.CreateInstance(ResourceProxy.GetProxy(type)); - resources.Add(document["_id"].AsObjectId.ToString(), resource); - - Warehouse.Put(resource, document["name"].AsString, this); - - - var parents = document["parents"].AsBsonArray; - var children = document["children"].AsBsonArray; - //var managers = document["managers"].AsBsonArray; - - var attributes = Parse(document["attributes"]).Then(x => { - resource.Instance.SetAttributes(x as Structure); - }); - - var bag = new AsyncBag(); - - foreach (var p in parents) - { - var ap = Warehouse.Get(p.AsString); - bag.Add(ap); - ap.Then((x) => - { - if (!resource.Instance.Parents.Contains(x)) - resource.Instance.Parents.Add(x); - }); - } - - foreach (var c in children) - { - - var ac = Warehouse.Get(c.AsString); - bag.Add(ac); - ac.Then((x) => - { - if (!resource.Instance.Children.Contains(x)) - resource.Instance.Children.Add(x); - }); - } - - // Apply store managers - foreach (var m in this.Instance.Managers) - resource.Instance.Managers.Add(m); - - /* - // load managers - foreach(var m in managers) - { - IPermissionsManager pm = (IPermissionsManager)Activator.CreateInstance(Type.GetType(m["classname"].AsString)); - var sr = Parse(m["settings"]); - bag.Add(sr); - sr.Then((x) => - { - pm.Initialize((Structure)x, resource); - resource.Instance.Managers.Add(pm); - }); - } - */ - - // Load values - var values = document["values"].AsBsonDocument; - - - foreach (var v in values) - { - - - var valueInfo = v.Value as BsonDocument; - - var av = Parse(valueInfo["value"]); - bag.Add(av); - av.Then((x) => - { - resource.Instance.LoadProperty(v.Name, (ulong)valueInfo["age"].AsInt64, valueInfo["modification"].ToUniversalTime(), x); - }); - } - - bag.Seal(); - - var rt = new AsyncReply(); - - bag.Then((x) => - { - rt.Trigger(resource); - }); - - return rt; - } - - IAsyncReply Parse(BsonValue value) - { - if (value.BsonType == BsonType.Document) - { - var doc = value.AsBsonDocument; - if (doc["type"] == 0) - { - return Warehouse.Get(doc["link"].AsString); - } // structure - else if (doc["type"] == 1) - { - var bag = new AsyncBag(); - var rt = new AsyncReply(); - - var bs = (BsonDocument)doc["values"].AsBsonDocument; - var s = new Structure(); - - foreach (var v in bs) - bag.Add(Parse(v.Value)); - - bag.Seal(); - bag.Then((x) => - { - for (var i = 0; i < x.Length; i++) - s[bs.GetElement(i).Name] = x[i]; - - rt.Trigger(s); - }); - - return rt; - } - else - return new AsyncReply(null); - } - else if (value.BsonType == BsonType.Array) - { - var array = value.AsBsonArray; - var bag = new AsyncBag(); - - foreach (var v in array) - bag.Add(Parse(v)); - - bag.Seal(); - - return bag; - } - else if (value.BsonType == BsonType.DateTime) - { - return new AsyncReply(value.ToUniversalTime()); - } - else - { - - return new AsyncReply(value.RawValue); - } - } - - public AsyncReply Get(string path) - { - var p = path.Split('/'); - if (p.Length == 2) - if (p[0] == "id") - { - // load from Id - - if (resources.ContainsKey(p[1])) - return new AsyncReply(resources[p[1]]); - else - return Fetch(p[1]); - } - - return new AsyncReply(null); - } - - public string Link(IResource resource) - { - return this.Instance.Name + "/id/" + (string)resource.Instance.Attributes["objectId"]; - } - - - string MakeTable(Type type) - { - var props = type.GetTypeInfo().GetProperties(); - - - foreach(var p in props) - { - var rp = p.GetCustomAttribute(); - if (rp == null) - continue; - - - } - } - - public bool Put(IResource resource) - { - - var attrs = resource.Instance.GetAttributes(); - - foreach (var kv in resources) - if (kv.Value == resource) - { - resource.Instance.Attributes.Add("objectId", kv.Key); - return true; - } - - var type = ResourceProxy.GetBaseType(resource); - - // insert the document - var document = new BsonDocument - { - { "classname", type.FullName + "," + type.GetTypeInfo().Assembly.GetName().Name }, - { "name", resource.Instance.Name }, - }; - - resourcesCollection.InsertOne(document); - resource.Instance.Attributes["objectId"] = document["_id"].ToString(); - - - // now update the document - // * insert first to get the object id, update values, attributes, children and parents after in case the same resource has a property references self - - var parents = new BsonArray(); - var children = new BsonArray(); - - var template = resource.Instance.Template; - - foreach (IResource c in resource.Instance.Children) - children.Add(c.Instance.Link); - - foreach (IResource p in resource.Instance.Parents) - parents.Add(p.Instance.Link); - - - var attrsDoc = ComposeStructure(attrs); - - - - - var values = new BsonDocument(); - - foreach (var pt in template.Properties) - { - var rt = pt.Info.GetValue(resource, null); - - values.Add(pt.Name, - new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, - { "modification", resource.Instance.GetModificationDate(pt.Index) }, - { "value", Compose(rt) } }); - } - - // var filter = Builders.Filter.Eq("_id", document["_id"]); - // var update = Builders.Update - // .Set("values", values); - // col.UpdateOne(filter, update); - - - /* - var document = new BsonDocument - { - { "parents", parents }, - { "children", children }, - { "attributes", attrsDoc }, - { "classname", resource.GetType().FullName + "," + resource.GetType().GetTypeInfo().Assembly.GetName().Name }, - { "name", resource.Instance.Name }, - { "values", values } - }; - */ - - var filter = Builders.Filter.Eq("_id", document["_id"]); - var update = Builders.Update - .Set("values", values).Set("parents", parents).Set("children", children).Set("attributes", attrsDoc); - resourcesCollection.UpdateOne(filter, update); - - - //resource.Instance.Attributes["objectId"] = document["_id"].ToString(); - - return true; - } - - - public BsonDocument ComposeStructure(Structure value) - { - var rt = new BsonDocument { { "type", 1 } }; - - var values = new BsonDocument(); - foreach (var i in value) - values.Add(i.Key, Compose(i.Value)); - - rt.Add("values", values); - return rt; - } - - public BsonArray ComposeVarArray(object[] array) - { - var rt = new BsonArray(); - - for (var i = 0; i < array.Length; i++) - rt.Add(Compose(array[i])); - - return rt; - } - - BsonArray ComposeStructureArray(Structure[] structures) - { - var rt = new BsonArray(); - - if (structures == null || structures?.Length == 0) - return rt; - - foreach (var s in structures) - rt.Add(ComposeStructure(s)); - - return rt; - } - - BsonArray ComposeResourceArray(IResource[] array) - { - var rt = new BsonArray(); - foreach (var r in array) - { - rt.Add(new BsonDocument { { "type", 0 }, { "link", r.Instance.Link } }); - - //if (r.Instance.Attributes.ContainsKey("objectId")) - - //rt.Add(new BsonObjectId(new ObjectId((string)r.Instance.Attributes["objectId"]))); - } - - return rt; - } - - private BsonValue Compose(object value) - { - var type = Codec.GetDataType(value, null); - - switch (type) - { - case DataType.Void: - // nothing to do; - return BsonNull.Value; - - case DataType.String: - return new BsonString((string)value); - - case DataType.Resource: - case DataType.DistributedResource: - - return new BsonDocument { { "type", 0 }, { "link", (value as IResource).Instance.Link } }; - - //return new BsonObjectId(new ObjectId((string)(value as IResource).Instance.Attributes["objectId"])); - - case DataType.Structure: - return ComposeStructure((Structure)value); - - case DataType.VarArray: - return ComposeVarArray((object[])value); - - case DataType.ResourceArray: - if (value is IResource[]) - return ComposeResourceArray((IResource[])value); - else - return ComposeResourceArray((IResource[])DC.CastConvert(value, typeof(IResource[]))); - - - case DataType.StructureArray: - return ComposeStructureArray((Structure[])value); - - - default: - return BsonValue.Create(value); - } - } - - public AsyncReply Retrieve(uint iid) - { - throw new NotImplementedException(); - } - - public AsyncReply Trigger(ResourceTrigger trigger) - { - - if (trigger == ResourceTrigger.Initialize) - { - - var collectionName = Instance.Attributes["Collection"] as string ?? "resources"; - var dbName = Instance.Attributes["Database"] as string ?? "Esyur"; - client = new MongoClient(Instance.Attributes["Connection"] as string ?? "mongodb://localhost"); - database = client.GetDatabase(dbName); - - resourcesCollection = this.database.GetCollection(collectionName); - - // return new AsyncReply(true); - - var filter = new BsonDocument(); - - var list = resourcesCollection.Find(filter).ToList(); - - - // if (list.Count == 0) - // return new AsyncBag(new IResource[0]); - - var bag = new AsyncBag(); - - for (var i = 0; i < list.Count; i++) - { - //Console.WriteLine("Loading {0}/{1}", i, list.Count); - bag.Add(Get("id/" + list[i]["_id"].AsObjectId.ToString())); - } - - bag.Seal(); - - var rt = new AsyncReply(); - - bag.Then((x) => { rt.Trigger(true); }); - - return rt; - } - else if (trigger == ResourceTrigger.Terminate) - { - // save all resources - foreach (var resource in resources.Values) - SaveResource(resource); - - return new AsyncReply(true); - } - else - return new AsyncReply(true); - } - - - public void SaveResource(IResource resource) - { - var attrs = resource.Instance.GetAttributes(); - - var parents = new BsonArray(); - var children = new BsonArray(); - var template = resource.Instance.Template; - - foreach (IResource c in resource.Instance.Children) - children.Add(c.Instance.Link); - - foreach (IResource p in resource.Instance.Parents) - parents.Add(p.Instance.Link); - - - var values = new BsonDocument(); - - foreach (var pt in template.Properties) - { - /* -#if NETSTANDARD1_5 - var pi = resource.GetType().GetTypeInfo().GetProperty(pt.Name); -#else - var pi = resource.GetType().GetProperty(pt.Name); -#endif -*/ - var rt = pt.Info.GetValue(resource, null); - - values.Add(pt.Name, - new BsonDocument { { "age", BsonValue.Create(resource.Instance.GetAge(pt.Index)) }, - { "modification", resource.Instance.GetModificationDate(pt.Index) }, - { "value", Compose(rt) } }); - - } - - var attrsDoc = ComposeStructure(attrs); - - var type = ResourceProxy.GetBaseType(resource); - - var document = new BsonDocument - { - { "parents", parents }, - { "children", children }, - {"attributes", attrsDoc }, - { "classname", type.FullName + "," + type.GetTypeInfo().Assembly.GetName().Name }, - { "name", resource.Instance.Name }, - { "_id", new BsonObjectId(new ObjectId(resource.Instance.Attributes["objectId"].ToString())) }, - {"values", values } - }; - - - - var filter = Builders.Filter.Eq("_id", document["_id"]); - - /* - var update = Builders.Update - .Set("values", values); - - var update = Builders.Update.Set("values", values).Set("parents", parents; - col.UpdateOne(filter, update); - - */ - - resourcesCollection.ReplaceOne(filter, document); - } - - public AsyncReply GetPropertyRecordByAge(IResource resource, string propertyName, ulong fromAge, ulong toAge) - { - var objectId = resource.Instance.Attributes["objectId"].ToString(); - - var record = this.database.GetCollection("record_" + objectId); - var builder = Builders.Filter; - - var filter = builder.Gte("age", fromAge) & builder.Lte("age", toAge) & builder.Eq("property", propertyName); - - var reply = new AsyncReply(); - - record.FindAsync(filter).ContinueWith((x) => - { - var values = ((Task>)x).Result.ToList(); - - var bag = new AsyncBag(); - - foreach (var v in values) - bag.Add(Parse(v["value"])); - - bag.Seal(); - - bag.Then((results) => - { - var list = new List(); - for (var i = 0; i < results.Length; i++) - list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime())); - - reply.Trigger(list.ToArray()); - }); - - }); - - return reply; - } - - public AsyncReply GetPropertyRecordByDate(IResource resource, string propertyName, DateTime fromDate, DateTime toDate) - { - var objectId = resource.Instance.Attributes["objectId"].ToString(); - - var record = this.database.GetCollection("record_" + objectId); - var builder = Builders.Filter; - - var filter = builder.Gte("date", fromDate) & builder.Lte("date", toDate) & builder.Eq("property", propertyName); - - var reply = new AsyncReply(); - - record.FindAsync(filter).ContinueWith((x) => - { - var values = ((Task>)x).Result.ToList(); - - var bag = new AsyncBag(); - - foreach (var v in values) - bag.Add(Parse(v["value"])); - - bag.Seal(); - - bag.Then((results) => - { - var list = new List(); - for (var i = 0; i < results.Length; i++) - list.Add(new PropertyValue(results[i], (ulong)values[i]["age"].AsInt64, values[i]["date"].ToUniversalTime())); - - reply.Trigger(list.ToArray()); - }); - - }); - - return reply; - } - - AsyncReply> GetRecordByAge(IResource resource, ulong fromAge, ulong toAge) - { - var properties = resource.Instance.Template.Properties.Where(x => x.Storage == StorageMode.Recordable).ToList(); - - var reply = new AsyncReply>(); - - AsyncBag bag = new AsyncBag(); - - foreach (var p in properties) - bag.Add(GetPropertyRecordByAge(resource, p.Name, fromAge, toAge)); - - bag.Seal(); - - bag.Then(x => - { - var list = new KeyList(); - - for (var i = 0; i < x.Length; i++) - list.Add(properties[i], x[i]); - - reply.Trigger(list); - }); - - return reply; - } - - public AsyncReply> GetRecord(IResource resource, DateTime fromDate, DateTime toDate) - { - var properties = resource.Instance.Template.Properties.Where(x => x.Storage == StorageMode.Recordable).ToList(); - - var reply = new AsyncReply>(); - - AsyncBag bag = new AsyncBag(); - - foreach (var p in properties) - bag.Add(GetPropertyRecordByDate(resource, p.Name, fromDate, toDate)); - - bag.Seal(); - - bag.Then(x => - { - var list = new KeyList(); - - for (var i = 0; i < x.Length; i++) - list.Add(properties[i], x[i]); - - reply.Trigger(list); - }); - - return reply; - } - - public bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime) - { - - var sql = $"UPDATE `{resource.Instance.Template.ClassName}` SET `{propertyName}` = @value, `{propertyName}_age` = @age, `{propertyName}_date` = @date WHERE `_id` = @id"; - - MySqlHelper.ExecuteNonQuery(connectionString, sql, - new MySqlParameter("@value", value), - new MySqlParameter("@age", age), - new MySqlParameter("@date", dateTime), - new MySqlParameter("@id", resource.Instance.Attributes["objectId"])); - - return true; - - } - - } -} diff --git a/Esyur.sln b/Esyur.sln index a0c9693..882387e 100644 --- a/Esyur.sln +++ b/Esyur.sln @@ -6,7 +6,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esyur", "Esyur\Esyur.csproj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esyur.Stores.MongoDB", "Esyur.Stores.MongoDB\Esyur.Stores.MongoDB.csproj", "{4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esyur.Stores.MySql", "Esyur.Stores.MySql\Esyur.Stores.MySql.csproj", "{7BD6148A-3335-411C-9189-3803B1824264}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esyur.Stores.EntityCore", "Esyur.Stores.EntityCore\Esyur.Stores.EntityCore.csproj", "{53DE5A30-CFA9-4DE7-A840-77CFF519D31B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -22,10 +22,10 @@ Global {4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Debug|Any CPU.Build.0 = Debug|Any CPU {4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Release|Any CPU.ActiveCfg = Release|Any CPU {4C90D4B3-8EA2-48AE-A2F9-2B722FCEF9C4}.Release|Any CPU.Build.0 = Release|Any CPU - {7BD6148A-3335-411C-9189-3803B1824264}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7BD6148A-3335-411C-9189-3803B1824264}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7BD6148A-3335-411C-9189-3803B1824264}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7BD6148A-3335-411C-9189-3803B1824264}.Release|Any CPU.Build.0 = Release|Any CPU + {53DE5A30-CFA9-4DE7-A840-77CFF519D31B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53DE5A30-CFA9-4DE7-A840-77CFF519D31B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53DE5A30-CFA9-4DE7-A840-77CFF519D31B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53DE5A30-CFA9-4DE7-A840-77CFF519D31B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Esyur/Data/Codec.cs b/Esyur/Data/Codec.cs index 3ec1dd7..f7d090a 100644 --- a/Esyur/Data/Codec.cs +++ b/Esyur/Data/Codec.cs @@ -35,6 +35,7 @@ using System.Linq; using System.Reflection; using Esyur.Resource.Template; using System.Runtime.CompilerServices; +using System.Collections; namespace Esyur.Data { @@ -1171,6 +1172,8 @@ namespace Esyur.Data if (value is IUserType) value = (value as IUserType).Get(); + + // value = (List<>)value.ToArray(); if (value is Func) //if (connection != null) @@ -1188,8 +1191,22 @@ namespace Esyur.Data var t = value.GetType(); + + // Convert ICollection to Array + if (!t.IsArray && typeof(ICollection).IsAssignableFrom(t)) + { + var col = t.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>)); + if (col.Count() == 0) + return (DataType.Void, null); + + var elementType = col.First().GetGenericArguments()[0]; + value = new ArrayList((ICollection)value).ToArray(elementType); + t = value.GetType(); + } + var isArray = t.IsArray; + if (isArray) t = t.GetElementType(); diff --git a/Esyur/Net/HTTP/HTTPServer.cs b/Esyur/Net/HTTP/HTTPServer.cs index 8872180..3514e8b 100644 --- a/Esyur/Net/HTTP/HTTPServer.cs +++ b/Esyur/Net/HTTP/HTTPServer.cs @@ -259,8 +259,8 @@ namespace Esyur.Net.HTTP foreach (var resource in filters) if (resource.Execute(sender)) return; - + sender.Response.Number = HTTPResponsePacket.ResponseCode.HTTP_SERVERERROR; sender.Send("Bad Request"); sender.Close(); } diff --git a/Esyur/Net/IIP/DistributedConnection.cs b/Esyur/Net/IIP/DistributedConnection.cs index c35ef28..4f00c46 100644 --- a/Esyur/Net/IIP/DistributedConnection.cs +++ b/Esyur/Net/IIP/DistributedConnection.cs @@ -800,6 +800,15 @@ namespace Esyur.Net.IIP } } + + [ResourceAttribute] + public string Username { get; set; } + + [ResourceAttribute] + public string Password { get; set; } + + [ResourceAttribute] + public string Domain { get; set; } /// /// Resource interface /// @@ -809,8 +818,8 @@ namespace Esyur.Net.IIP { if (trigger == ResourceTrigger.Open) { - if (Instance.Attributes.ContainsKey("username") - && Instance.Attributes.ContainsKey("password")) + if (Username != null // Instance.Attributes.ContainsKey("username") + && Password != null)/// Instance.Attributes.ContainsKey("password")) { // assign domain from hostname if not provided @@ -818,16 +827,16 @@ namespace Esyur.Net.IIP var address = host[0]; var port = ushort.Parse(host[1]); - var username = Instance.Attributes["username"].ToString(); + var username = Username;// Instance.Attributes["username"].ToString(); - var domain = Instance.Attributes.ContainsKey("domain") ? Instance.Attributes["domain"].ToString() : address; + var domain = Domain != null ? Domain : address;// Instance.Attributes.ContainsKey("domain") ? Instance.Attributes["domain"].ToString() : address; session = new Session(new ClientAuthentication() , new HostAuthentication()); session.LocalAuthentication.Domain = domain; session.LocalAuthentication.Username = username; - localPassword = DC.ToBytes(Instance.Attributes["password"].ToString()); + localPassword = DC.ToBytes(Password);// Instance.Attributes["password"].ToString()); openReply = new AsyncReply(); var sock = new TCPSocket(); diff --git a/Esyur/Net/IIP/DistributedConnectionProtocol.cs b/Esyur/Net/IIP/DistributedConnectionProtocol.cs index a88e296..b615925 100644 --- a/Esyur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esyur/Net/IIP/DistributedConnectionProtocol.cs @@ -413,7 +413,7 @@ namespace Esyur.Net.IIP { Fetch(resourceId).Then(resource => { - resource.Instance.Attributes["name"] = name.GetString(0, (uint)name.Length); + resource.Instance.Variables["name"] = name.GetString(0, (uint)name.Length); }); } @@ -451,7 +451,8 @@ namespace Esyur.Net.IIP r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; // r.Instance.Children.OnAdd -= Children_OnAdd; // r.Instance.Children.OnRemoved -= Children_OnRemoved; - r.Instance.Attributes.OnModified -= Attributes_OnModified; + + //r.Instance.Attributes.OnModified -= Attributes_OnModified; // subscribe r.Instance.ResourceEventOccurred += Instance_EventOccurred; @@ -459,7 +460,8 @@ namespace Esyur.Net.IIP r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; //r.Instance.Children.OnAdd += Children_OnAdd; //r.Instance.Children.OnRemoved += Children_OnRemoved; - r.Instance.Attributes.OnModified += Attributes_OnModified; + + //r.Instance.Attributes.OnModified += Attributes_OnModified; // add it to attached resources so GC won't remove it from memory attachedResources.Add(r); @@ -564,7 +566,8 @@ namespace Esyur.Net.IIP r.Instance.ResourceDestroyed -= Instance_ResourceDestroyed; //r.Instance.Children.OnAdd -= Children_OnAdd; //r.Instance.Children.OnRemoved -= Children_OnRemoved; - r.Instance.Attributes.OnModified -= Attributes_OnModified; + + //r.Instance.Attributes.OnModified -= Attributes_OnModified; // subscribe r.Instance.ResourceEventOccurred += Instance_EventOccurred; @@ -572,7 +575,8 @@ namespace Esyur.Net.IIP r.Instance.ResourceDestroyed += Instance_ResourceDestroyed; //r.Instance.Children.OnAdd += Children_OnAdd; //r.Instance.Children.OnRemoved += Children_OnRemoved; - r.Instance.Attributes.OnModified += Attributes_OnModified; + + //r.Instance.Attributes.OnModified += Attributes_OnModified; // reply ok SendReply(IIPPacket.IIPPacketAction.ReattachResource, callback) diff --git a/Esyur/Net/Sockets/TCPSocket.cs b/Esyur/Net/Sockets/TCPSocket.cs index 5a77445..078973d 100644 --- a/Esyur/Net/Sockets/TCPSocket.cs +++ b/Esyur/Net/Sockets/TCPSocket.cs @@ -406,8 +406,6 @@ namespace Esyur.Net.Sockets Console.WriteLine("Level 2 {0}", ex2); } - - Global.Log("TCPSocket", LogType.Error, ex.ToString()); } } diff --git a/Esyur/Proxy/ResourceProxy.cs b/Esyur/Proxy/ResourceProxy.cs index d9ef2d0..0275d6c 100644 --- a/Esyur/Proxy/ResourceProxy.cs +++ b/Esyur/Proxy/ResourceProxy.cs @@ -48,8 +48,8 @@ namespace Esyur.Proxy #if NETSTANDARD var typeInfo = type.GetTypeInfo(); - if (typeInfo.IsSealed) - throw new Exception("Sealed class can't be proxied."); + if (typeInfo.IsSealed || typeInfo.IsAbstract) + throw new Exception("Sealed/Abastract classes can't be proxied."); var props = from p in typeInfo.GetProperties() where p.CanWrite && p.GetSetMethod().IsVirtual && diff --git a/Esyur/Resource/IResource.cs b/Esyur/Resource/IResource.cs index 178a637..1f2908a 100644 --- a/Esyur/Resource/IResource.cs +++ b/Esyur/Resource/IResource.cs @@ -28,12 +28,13 @@ using System.Linq; using System.Text; using Esyur.Data; using Esyur.Core; +using System.ComponentModel; namespace Esyur.Resource { public delegate bool QueryFilter(T value); - public interface IResource : IDestructible + public interface IResource : IDestructible///, INotifyPropertyChanged { AsyncReply Trigger(ResourceTrigger trigger); diff --git a/Esyur/Resource/IStore.cs b/Esyur/Resource/IStore.cs index 281720b..1f315fb 100644 --- a/Esyur/Resource/IStore.cs +++ b/Esyur/Resource/IStore.cs @@ -30,6 +30,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Esyur.Security.Permissions; +using Esyur.Security.Authority; namespace Esyur.Resource { @@ -43,6 +45,13 @@ namespace Esyur.Resource bool Modify(IResource resource, string propertyName, object value, ulong age, DateTime dateTime); bool Remove(IResource resource); + //bool RemoveAttributes(IResource resource, string[] attributes = null); + + //Structure GetAttributes(IResource resource, string[] attributes = null); + + //bool SetAttributes(IResource resource, Structure attributes, bool clearAttributes = false); + + AsyncReply AddChild(IResource parent, IResource child); AsyncReply RemoveChild(IResource parent, IResource child); diff --git a/Esyur/Resource/Instance.cs b/Esyur/Resource/Instance.cs index 4d1a196..5d67a08 100644 --- a/Esyur/Resource/Instance.cs +++ b/Esyur/Resource/Instance.cs @@ -20,22 +20,14 @@ namespace Esyur.Resource { string name; - //IQueryable children;// - //AutoList children;// = new AutoList(); WeakReference resource; IStore store; - //AutoList parents;// = new AutoList(); - //bool inherit; ResourceTemplate template; - - AutoList managers;// = new AutoList(); + AutoList managers; public delegate void ResourceModifiedEvent(IResource resource, string propertyName, object newValue); - //public delegate void ResourceEventOccurredEvent(IResource resource, string eventName, string[] users, DistributedConnection[] connections, object[] args); - public delegate void ResourceEventOccurredEvent(IResource resource, object issuer, Session[] receivers, string eventName, object[] args); - public delegate void ResourceDestroyedEvent(IResource resource); public event ResourceModifiedEvent ResourceModified; @@ -44,7 +36,7 @@ namespace Esyur.Resource bool loading = false; - KeyList attributes; + //KeyList attributes; List ages = new List(); List modificationDates = new List(); @@ -53,17 +45,18 @@ namespace Esyur.Resource uint id; + public KeyList Variables { get; } = new KeyList(); /// /// Instance attributes are custom properties associated with the instance, a place to store information by IStore. /// - public KeyList Attributes - { - get - { - return attributes; - } - } + //public KeyList Attributes + //{ + // get + // { + // return attributes; + // } + //} public override string ToString() { @@ -72,6 +65,19 @@ namespace Esyur.Resource public bool RemoveAttributes(string[] attributes = null) { + + return false; + + /* + IResource res; + + if (!resource.TryGetTarget(out res)) + return false; + + return store.RemoveAttributes(res, attributes); + */ + + /* if (attributes == null) this.attributes.Clear(); else @@ -81,10 +87,31 @@ namespace Esyur.Resource } return true; + */ } public Structure GetAttributes(string[] attributes = null) { + // @TODO + Structure rt = new Structure(); + + if (attributes != null) + { + for (var i = 0; i < attributes.Length; i++) + { + var at = template.GetAttributeTemplate(attributes[i]); + if (at != null) + { + + } + } + } + + return rt; + + + + /* var st = new Structure(); if (attributes == null) @@ -132,10 +159,31 @@ namespace Esyur.Resource } return st; + */ } public bool SetAttributes(Structure attributes, bool clearAttributes = false) { + + // @ TODO + IResource res; + + if (resource.TryGetTarget(out res)) + { + foreach (var kv in attributes) + { + var at = template.GetAttributeTemplate(kv.Key); + + if (at != null) + if (at.Info.CanWrite) + at.Info.SetValue(res, kv.Value); + } + } + + return true; + + + /* try { @@ -183,6 +231,7 @@ namespace Esyur.Resource } return true; + */ } /* @@ -758,12 +807,15 @@ namespace Esyur.Resource IResource res; if (this.resource.TryGetTarget(out res)) { + //return store.Applicable(res, session, action, member, inquirer); + foreach (IPermissionsManager manager in managers) { var r = manager.Applicable(res, session, action, member, inquirer); if (r != Ruling.DontCare) return r; } + } return Ruling.DontCare; @@ -790,7 +842,7 @@ namespace Esyur.Resource this.name = name; this.instanceAge = age; - this.attributes = new KeyList(this); + //this.attributes = new KeyList(this); //children = new AutoList(this); //parents = new AutoList(this); managers = new AutoList(this); diff --git a/Esyur/Resource/ResourceAttribute.cs b/Esyur/Resource/ResourceAttribute.cs new file mode 100644 index 0000000..06cf302 --- /dev/null +++ b/Esyur/Resource/ResourceAttribute.cs @@ -0,0 +1,42 @@ +/* + +Copyright (c) 2020 Ahmed Kh. Zamil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Esyur.Resource +{ + + [AttributeUsage(AttributeTargets.Property)] + public class ResourceAttribute : System.Attribute + { + + public ResourceAttribute() + { + + } + } +} diff --git a/Esyur/Resource/Template/AttributeTemplate.cs b/Esyur/Resource/Template/AttributeTemplate.cs new file mode 100644 index 0000000..0ef7903 --- /dev/null +++ b/Esyur/Resource/Template/AttributeTemplate.cs @@ -0,0 +1,26 @@ +using Esyur.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Esyur.Resource.Template +{ + public class AttributeTemplate : MemberTemplate + { + public PropertyInfo Info + { + get; + set; + } + + + public AttributeTemplate(ResourceTemplate template, byte index, string name) + : base(template, MemberType.Attribute, index, name) + { + + } + } +} diff --git a/Esyur/Resource/Template/MemberTemplate.cs b/Esyur/Resource/Template/MemberTemplate.cs index a28c94a..de520db 100644 --- a/Esyur/Resource/Template/MemberTemplate.cs +++ b/Esyur/Resource/Template/MemberTemplate.cs @@ -14,6 +14,7 @@ namespace Esyur.Resource.Template Function = 0, Property = 1, Event = 2, + Attribute = 3 } public byte Index => index; diff --git a/Esyur/Resource/Template/ResourceTemplate.cs b/Esyur/Resource/Template/ResourceTemplate.cs index 2aedeb1..d28302d 100644 --- a/Esyur/Resource/Template/ResourceTemplate.cs +++ b/Esyur/Resource/Template/ResourceTemplate.cs @@ -19,6 +19,7 @@ namespace Esyur.Resource.Template List functions = new List(); List events = new List(); List properties = new List(); + List attributes = new List(); int version; //bool isReady; @@ -88,6 +89,14 @@ namespace Esyur.Resource.Template return null; } + public AttributeTemplate GetAttributeTemplate(string attributeName) + { + foreach (var i in attributes) + if (i.Name == attributeName) + return i; + return null; + } + public Guid ClassId { get { return classId; } @@ -156,21 +165,31 @@ namespace Esyur.Resource.Template foreach (var pi in propsInfo) { - var ps = (ResourceProperty[])pi.GetCustomAttributes(typeof(ResourceProperty), true); - if (ps.Length > 0) + var rp = pi.GetCustomAttribute(true); + + if (rp != null) { - var pt = new PropertyTemplate(this, i++, pi.Name, ps[0].ReadExpansion, ps[0].WriteExpansion, ps[0].Storage); + var pt = new PropertyTemplate(this, i++, pi.Name, rp.ReadExpansion, rp.WriteExpansion, rp.Storage); pt.Info = pi; - pt.Serilize = ps[0].Serialize; + pt.Serilize = rp.Serialize; properties.Add(pt); } + + var ra = pi.GetCustomAttribute(true); + + if (ra != null) + { + var at = new AttributeTemplate(this, i++, pi.Name); + at.Info = pi; + attributes.Add(at); + } } i = 0; foreach (var ei in eventsInfo) { - var es = (ResourceEvent[])ei.GetCustomAttributes(typeof(ResourceEvent), true); + var es = ei.GetCustomAttributes(true).ToArray(); if (es.Length > 0) { var et = new EventTemplate(this, i++, ei.Name, es[0].Expansion); @@ -181,7 +200,7 @@ namespace Esyur.Resource.Template i = 0; foreach (MethodInfo mi in methodsInfo) { - var fs = (ResourceFunction[])mi.GetCustomAttributes(typeof(ResourceFunction), true); + var fs = mi.GetCustomAttributes(true).ToArray(); if (fs.Length > 0) { var ft = new FunctionTemplate(this, i++, mi.Name, mi.ReturnType == typeof(void), fs[0].Expansion); diff --git a/Esyur/Resource/Warehouse.cs b/Esyur/Resource/Warehouse.cs index 75c0bf8..52fa54c 100644 --- a/Esyur/Resource/Warehouse.cs +++ b/Esyur/Resource/Warehouse.cs @@ -501,10 +501,9 @@ namespace Esyur.Resource } - public static T New(string name, IStore store = null, IResource parent = null, IPermissionsManager manager = null, Structure attributes = null, Structure arguments = null, Structure properties = null) - where T : IResource + public static IResource New(Type type, string name, IStore store = null, IResource parent = null, IPermissionsManager manager = null, Structure attributes = null, Structure arguments = null, Structure properties = null) { - var type = ResourceProxy.GetProxy(); + type = ResourceProxy.GetProxy(type); /* @@ -544,7 +543,7 @@ namespace Esyur.Resource { foreach (var p in properties) { - var pi = typeof(T).GetProperty(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly); + var pi = type.GetProperty(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly); if (pi != null) pi.SetValue(res, p.Value); } @@ -553,7 +552,14 @@ namespace Esyur.Resource if (store != null || parent != null || res is IStore) Put(res, name, store, parent, null, 0, manager, attributes); - return (T)res; + return res; + + } + + public static T New(string name, IStore store = null, IResource parent = null, IPermissionsManager manager = null, Structure attributes = null, Structure arguments = null, Structure properties = null) + where T : IResource + { + return (T)New(typeof(T), name, store, parent, manager, attributes, arguments, properties); } /// diff --git a/Esyur/Stores/MemoryStore.cs b/Esyur/Stores/MemoryStore.cs index 25b847b..cb7e1a3 100644 --- a/Esyur/Stores/MemoryStore.cs +++ b/Esyur/Stores/MemoryStore.cs @@ -45,8 +45,8 @@ namespace Esyur.Stores { resources.Add(resource.Instance.Id, resource);// new WeakReference(resource)); - resource.Instance.Attributes["children"] = new AutoList(resource.Instance); - resource.Instance.Attributes["parents"] = new AutoList(resource.Instance); + resource.Instance.Variables["children"] = new AutoList(resource.Instance); + resource.Instance.Variables["parents"] = new AutoList(resource.Instance); return true; } @@ -94,7 +94,7 @@ namespace Esyur.Stores { if (parent.Instance.Store == this) { - (parent.Instance.Attributes["children"] as AutoList).Add(child); + (parent.Instance.Variables["children"] as AutoList).Add(child); return new AsyncReply(true); } else @@ -111,7 +111,7 @@ namespace Esyur.Stores if (resource.Instance.Store == this) { - (resource.Instance.Attributes["parents"] as AutoList).Add(parent); + (resource.Instance.Variables["parents"] as AutoList).Add(parent); return new AsyncReply(true); } else @@ -125,7 +125,7 @@ namespace Esyur.Stores public AsyncBag Children(IResource resource, string name) where T : IResource { - var children = (resource.Instance.Attributes["children"] as AutoList); + var children = (resource.Instance.Variables["children"] as AutoList); if (name == null) return new AsyncBag(children.Where(x=>x is T).Select(x=>(T)x).ToArray()); @@ -136,7 +136,7 @@ namespace Esyur.Stores public AsyncBag Parents(IResource resource, string name) where T : IResource { - var parents = (resource.Instance.Attributes["parents"] as AutoList); + var parents = (resource.Instance.Variables["parents"] as AutoList); if (name == null) return new AsyncBag(parents.Where(x => x is T).Select(x => (T)x).ToArray());