Example #1
0
        public IxLock(IIxInstanceLock instanceLock)
        {
            Critical.Assert(instanceLock != null, "Lock target should not be null.");

            _instanceLock = instanceLock;
            _target       = (T)_instanceLock.Target.Object;
        }
Example #2
0
 /// <summary>
 /// Processes UoW disposed event.
 /// </summary>
 /// <param name="uow">Disposed UoW.</param>
 /// <remarks>SyncRoot <c>lock</c> required here.</remarks>
 internal void OnUowDisposed(TUnitOfWork uow)
 {
     if (!_openedUoWs.TryRemove(uow, out var _))
     {
         Critical.Assert(false, "Wrong Unit of Work or double dispose.");
     }
 }
Example #3
0
        /// <inheritdoc/>
        public void RemoveLock(IIxInstanceLock instanceLock)
        {
            if (instanceLock == null)
            {
                throw new ArgumentNullException(nameof(instanceLock));
            }

            EnsureTreeLocked();

            if (ReferenceEquals(instanceLock, _initTempLock))
            {
                Critical.Assert(
                    _objectCreationTask != null,
                    "You need to setup instance object factory before releasing creator lock.");
                Critical.Assert(
                    _objectCreationTask.Value.IsCompleted,
                    "Creator lock should be removed only after object instantiation completes.");

                _initTempLock = null;
            }


            // --------- We are under tree lock --------------
            if (!_locks.Remove(instanceLock))
            {
                Critical.Assert(false, "Lock was not registered in the target or already removed.");
            }

            UpdateDisposeSuspendState();

            UpdateChildrenDisposeCompleteSuspendState();
        }
Example #4
0
 /// <inheritdoc/>
 public override async ValueTask <IIxInstanceLock> GetInstance(
     IIxInstance parentInstance,
     IxIdentifier identifier,
     IxHost.IxResolveContext context,
     [CanBeNull] IxResolveFrame frame)
 {
     Critical.Assert(false, "Not supported.");
     return(null);
 }
Example #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="IxInstancePinLock"/> class.
        /// </summary>
        /// <param name="target">IndirectX instance.</param>
        public IxInstancePinLock(IIxInstance target)
        {
            Critical.Assert(target != null, "Pin lock target should not be null.");

            Target = target;

            lock (target.ProviderNode.Host.InstanceTreeSyncRoot)
            {
                Target.AddLock(this);
            }
        }
Example #6
0
 private void UpdateChildrenDisposeCompleteSuspendState()
 {
     try
     {
         _childrenDisposeCompleted.SuspendTrigger(_locks.Any());
     }
     catch (InvalidOperationException)
     {
         Critical.Assert(false, "Cannot set child lock, full dispose was completed.");
     }
 }
Example #7
0
        /// <summary>
        /// Registers persistence <c>plugin</c>.
        /// </summary>
        /// <param name="plugin">Persistence <c>plugin</c>.</param>
        internal void RegisterPlugin(PersistencePluginBase <TPersistence, TUnitOfWork> plugin)
        {
            if (plugin == null)
            {
                throw new ArgumentNullException(nameof(plugin));
            }

            Critical.Assert(!_isInitialized, "You cannot register plugin after persistence become initialized.");

            _plugins.Add(plugin);
        }
Example #8
0
        private async ValueTask <IIxInstanceLock> RegistrationScopeBinder(
            IIxInstance originInstance,
            IxResolvePath resolvePath,
            IxResolveContext context,
            [CanBeNull] IxResolveFrame frame,
            IxResolveBoundDelegate resolveBound)
        {
            IIxInstance curInstance = originInstance;

            Critical.Assert(resolvePath.Path.Any(), "Registration scope binder does not support empty path.");

            lock (InstanceTreeSyncRoot)
            {
                while (curInstance != null)
                {
                    if (curInstance.ProviderNode == resolvePath.Root)
                    {
                        break;
                    }

                    curInstance = curInstance.ParentInstance;
                }
            }

            if (curInstance == null)
            {
                throw new InvalidOperationException("Resolve algorithms problems");
            }

            Func <IIxInstance, int, ValueTask <IIxInstanceLock> > resolvePathElements = null;

            resolvePathElements = async(parentInstance, index) =>
            {
                if (index < resolvePath.Path.Count - 1)
                {
                    using (IIxInstanceLock instanceLock = await Resolve(
                               parentInstance,
                               resolvePath.Path[index].Identifier,
                               context,
                               frame))
                    {
                        return(await resolvePathElements(instanceLock.Target, index + 1));
                    }
                }

                return(await resolveBound(parentInstance, resolvePath.Path.Last(), context));
            };

            IIxInstanceLock resultInstanceLock = await resolvePathElements(curInstance, 0);

            return(resultInstanceLock);
        }
            public object GetData(IxProviderNode providerNode)
            {
                Critical.CheckedAssert(providerNode != null, "providerNode != null");

                if (!Monitor.IsEntered(_originInstance.ProviderNode.Host.InstanceTreeSyncRoot))
                {
                    Critical.Assert(false, "Data manipulations should be performed under lock.");
                }

                _rootContext.ProvidersData.TryGetValue(providerNode, out object result);

                return(result);
            }
Example #10
0
        /// <inheritdoc/>
        public void AddOwnedLock(IIxInstanceLock instanceLock)
        {
            if (instanceLock == null)
            {
                throw new ArgumentNullException(nameof(instanceLock));
            }

            EnsureTreeLocked();
            if (!_ownedLocks.Add(instanceLock))
            {
                Critical.Assert(false, "Owned Lock already registered in the owner.");
            }
        }
Example #11
0
        /// <inheritdoc/>
        public void RemoveOwnedLock(IIxInstanceLock instanceLock)
        {
            if (instanceLock == null)
            {
                throw new ArgumentNullException(nameof(instanceLock));
            }

            EnsureTreeLocked();

            // --------- We are under tree lock --------------
            if (!_ownedLocks.Remove(instanceLock))
            {
                Critical.Assert(false, "Owned lock was not registered in the owner or already removed.");
            }
        }
Example #12
0
 private void UpdateDisposeSuspendState()
 {
     try
     {
         bool nonChildLocksExists = !Locks.All(x => x is IxInstanceChildLock);
         SetDisposeSuspended(nonChildLocksExists);
         if (!nonChildLocksExists && ProviderNode.AutoDisposeEnabled)
         {
             DisposeAsync();
         }
     }
     catch (InvalidOperationException)
     {
         Critical.Assert(false, "Cannot set lock, self dispose was started.");
     }
 }
Example #13
0
        /// <summary>
        /// Initializes object creation task.
        /// </summary>
        /// <param name="objectCreateTask">The object creation task.</param>
        protected void SetObjectCreationTask(ValueTask <object> objectCreateTask)
        {
            // If everything fine this method will be called from one thread and only once.
            // We can skip thread safety check for this method.
            if (objectCreateTask == null)
            {
                throw new ArgumentNullException(nameof(objectCreateTask));
            }

            EnsureTreeLocked();

            Critical.Assert(
                _objectCreationTask == null,
                "Instance already initialized, you cannot init Object property twice.");

            _objectCreationTask = ObjectFactoryProxy(objectCreateTask);
        }
Example #14
0
        /// <inheritdoc/>
        public void AddLock(IIxInstanceLock instanceLock)
        {
            if (instanceLock == null)
            {
                throw new ArgumentNullException(nameof(instanceLock));
            }

            EnsureTreeLocked();

            bool inserted = _locks.Add(instanceLock);

            Critical.Assert(inserted, "Lock already registered in the target instance.");

            UpdateDisposeSuspendState();

            UpdateChildrenDisposeCompleteSuspendState();
        }
Example #15
0
        public object GetData(IxProviderNode providerNode)
        {
            if (providerNode == null)
            {
                throw new ArgumentNullException(nameof(providerNode));
            }

            if (!Monitor.IsEntered(ProviderNode.Host.InstanceTreeSyncRoot))
            {
                Critical.Assert(false, "Data manipulations should be performed under lock.");
            }

            object result;

            ChildrenData.TryGetValue(providerNode, out result);

            return(result);
        }
            /// <inheritdoc/>
            public void SetData(IxProviderNode providerNode, [CanBeNull] object data)
            {
                Critical.CheckedAssert(providerNode != null, "providerNode != null");

                if (!Monitor.IsEntered(_originInstance.ProviderNode.Host.InstanceTreeSyncRoot))
                {
                    Critical.Assert(false, "Data manipulations should be performed under tree lock.");
                }

                if (data == null)
                {
                    _rootContext.ProvidersData.Remove(providerNode);
                }
                else
                {
                    _rootContext.ProvidersData[providerNode] = data;
                }
            }
Example #17
0
        /// <inheritdoc/>
        protected override async Task DisposeAsyncCore()
        {
            // Under tree lock here, until first await.
            EnsureTreeLocked();

            try
            {
                if (_locks.Any(x => !(x is IxInstanceChildLock)))
                {
                    Critical.Assert(
                        false,
                        "Dependencies schema problem, after instance object disposed no any lock are allowed.");
                }

                if (!ObjectCreationTask.IsFaulted)
                {
                    // Only fully-initialized instance should be self-disposed.
                    await SelfDispose();
                }

                // This call is not required.
                ////UpdateChildrenDisposeCompleteSuspendState();
                _childrenDisposeCompleted.Set();

                // Sync or async execution here.
            }
            finally
            {
                // Sync or async execution here.
                // ------------------------------------
                lock (ProviderNode.Host.InstanceTreeSyncRoot)
                {
                    // Freeing all owned locks.
                    while (OwnedLocks.Any())
                    {
                        // Here other objects can dispose synchronously.
                        OwnedLocks.First().Dispose();
                    }
                }

                await _childrenDisposeCompleted;
            }
        }
Example #18
0
 /// <inheritdoc/>
 public void Dispose()
 {
     try
     {
         try
         {
             _instanceLock?.Dispose();
         }
         catch (Exception ex) when(ex.IsProcessable())
         {
             Critical.Assert(false, "Dispose should not raise any error.");
         }
     }
     catch
     {
         // Dispose should decouple errors propagation.
         // Usually dispose errors relates only to disposing component, but not to it's caller.
     }
 }
Example #19
0
        /// <inheritdoc/>
        public void Dispose()
        {
            try
            {
                Critical.Assert(!_disposed, "Lock already disposed.");

                lock (Target.ProviderNode.Host.InstanceTreeSyncRoot)
                {
                    Critical.Assert(!_disposed, "Lock already disposed.");

                    _disposed = true;

                    Target.RemoveLock(this);
                }
            }
            catch
            {
                // Dispose should decouple errors propagation.
                // Usually dispose errors relates only to disposing component, but not to it's caller.
            }
        }
Example #20
0
        /// <inheritdoc/>
        public void SetData(IxProviderNode providerNode, [CanBeNull] object data)
        {
            if (providerNode == null)
            {
                throw new ArgumentNullException(nameof(providerNode));
            }

            if (!Monitor.IsEntered(ProviderNode.Host.InstanceTreeSyncRoot))
            {
                Critical.Assert(false, "Data manipulations should be performed under tree lock.");
            }

            if (data == null)
            {
                ChildrenData.Remove(providerNode);
            }
            else
            {
                ChildrenData[providerNode] = data;
            }
        }
Example #21
0
 /// <summary>
 /// Initializes a new instance of the <see cref="IxArgumentProvider"/> class.
 /// </summary>
 /// <param name="host">IndirectX host.</param>
 public IxArgumentProvider(IxHost host)
     : base(
         host,
         null,
         new IxStdProviderConfig
 {
     Identifier = new IxIdentifier(typeof(object)),
 },
         null,
         identifier => true,
         identifier => true,
         identifier => true,
         async(a, b, c, d, e) =>
 {
     Critical.Assert(false, "Not supported.");
     return(null);
 },
         false,
         obj => TaskEx.CompletedTask)
 {
 }
Example #22
0
        /// <inheritdoc/>
        public IUnitOfWorkImpl OpenUnitOfWork()
        {
            VerifyInitialized();

            TUnitOfWork uow = CreateUnitOfWork();

            _openedUoWs.TryAdd(uow, default);

            try
            {
                // Handler should never rise an exception.
                OnUnitOfWorkOpened(uow);
            }
            catch (Exception ex)
            {
                Critical.Assert(
                    false,
                    $"UnitOfWorkOpened handlers should never rise any exception. Error = {ex.Message}");
            }

            return(uow);
        }
Example #23
0
        /// <summary>
        /// Initializes a new instance of the <see cref="IxReferenceLock"/> class.
        /// </summary>
        /// <param name="target">The instance to lock.</param>
        /// <param name="owner">The owner of this lock.</param>
        public IxReferenceLock(IIxInstance target, IIxInstance owner)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            if (owner == null)
            {
                throw new ArgumentNullException(nameof(owner));
            }

            Critical.Assert(!ReferenceEquals(target, owner), "Cannot create reference from self to self.");

            Target = target;
            Owner  = owner;

            lock (Target.ProviderNode.Host.InstanceTreeSyncRoot)
            {
                Target.AddLock(this);
                Owner.AddOwnedLock(this);
            }
        }
Example #24
0
        /// <summary>
        /// Creates or updates entity.
        /// </summary>
        /// <remarks>
        /// Update or Create operations are performed in the critical section, so left any processing out-of those functions.
        /// </remarks>
        /// <param name="entityKey">The entity key.</param>
        /// <param name="updateAction">The update action. It will be called when entity with the specified key exists.</param>
        /// <param name="createFunc">The create function. It will be called when entity with the specified key not exists.</param>
        public void CreateOrUpdateEntity(TKey entityKey, Action <TEntity> updateAction, Func <TEntity> createFunc)
        {
            VxArgs.NotNull(entityKey, nameof(entityKey));
            VxArgs.NotNull(updateAction, nameof(updateAction));
            VxArgs.NotNull(createFunc, nameof(createFunc));

            lock (_entities)
            {
                if (_entities.TryGetValue(entityKey, out var entity))
                {
                    updateAction(entity);
                }
                else
                {
                    TEntity newEntity = createFunc();

                    // Following max capacity rule.
                    if (MaxCapacity != null && _gcFifoQueue != null)
                    {
                        if (_gcFifoQueue.Count >= MaxCapacity)
                        {
                            if (_gcFifoQueue.TryDequeue(out var itemToRemove))
                            {
                                _entities.Remove(itemToRemove.Key);
                            }
                        }

                        _gcFifoQueue.AddFirst(entityKey, default);
                    }

                    _entities.Add(entityKey, newEntity);
                    Critical.Assert(
                        newEntity.Key.Equals(entityKey),
                        "Created entity should have the same key as was queried to the CreateOrUpdateEntity method.");
                }
            }
        }
Example #25
0
        private ResolveDelegate SelfToChildrenResolver(ResolveDelegate next)
        {
            return(async(originInstance, identifier, context, frame) =>
            {
                if (identifier.Name == null)
                {
                    IxResolvePath resolvePath;
                    if (originInstance.ProviderNode.VisibleNodes.TryGetValue(identifier, out resolvePath))
                    {
                        if (!resolvePath.Path.Any())
                        {
                            lock (InstanceTreeSyncRoot)
                            {
                                IIxInstance curInstance = originInstance;
                                while (curInstance != null)
                                {
                                    if (curInstance.ProviderNode == resolvePath.Root)
                                    {
                                        break;
                                    }

                                    curInstance = curInstance.ParentInstance;
                                }

                                Critical.Assert(
                                    curInstance != null,
                                    "Instance of an appropriate provider should be found.");

                                return new IxInstancePinLock(curInstance);
                            }
                        }
                    }
                }

                return await next(originInstance, identifier, context, frame);
            });
        }
        private InstanceFactoryBuilderDelegate ClassInstanceFactoryBuilder(
            InstanceFactoryBuilderDelegate next)
        {
            return(factoryConfig =>
            {
                TypeInfo configTypeInfo = factoryConfig.GetType().GetTypeInfo();

                if (configTypeInfo.IsGenericType &&
                    (configTypeInfo.GetGenericTypeDefinition() == typeof(IxClassInstanceBuilderConfig <>)))
                {
                    TypeInfo instanceClass = configTypeInfo.GenericTypeArguments[0].GetTypeInfo();
                    ConstructorInfo[] constructors =
                        instanceClass.DeclaredConstructors.Where(x => !x.IsStatic).ToArray();
                    if (constructors.Length == 0)
                    {
                        // Currently impossible case.
                        throw new IxConfigurationException(
                            $"Cannot use IxClassInstanceFactory because no any constructors found in the class {instanceClass.FullName}.");
                    }

                    if (constructors.Length > 1)
                    {
                        throw new IxConfigurationException(
                            $"Cannot use IxClassInstanceFactory because more than one constructors defined in the class {instanceClass.FullName}.");
                    }

                    ConstructorInfo constructorInfo = constructors.Single();

                    HashSet <IxIdentifier> dependencies =
                        constructorInfo.GetParameters().Select(x => new IxIdentifier(x.ParameterType)).ToHashSet();
                    if (dependencies.Count != constructorInfo.GetParameters().Length)
                    {
                        throw new IxConfigurationException(
                            "Multiple parameters with the same type not supported by IxClassRawFactory.");
                    }

                    // TODO: Add tests for this feature
                    List <RequireAttribute> requireAttributes =
                        constructorInfo.GetCustomAttributes <RequireAttribute>().ToList();
                    foreach (RequireAttribute requireAttribute in requireAttributes)
                    {
                        if (!dependencies.Add(new IxIdentifier(requireAttribute.Type)))
                        {
                            throw new IxConfigurationException(
                                "Multiple parameters with the same type not supported by IxClassRawFactory.");
                        }
                    }

                    // instance argument here is half-instantiated instance.
                    return new IxInstanceFactory(
                        (instance, parentInstance, resolveContext, frame) => ResolveList(
                            instance,
                            dependencies,
                            resolveContext,
                            frame,
                            async resolvedDependencies =>
                    {
                        try
                        {
                            object[] arguments = constructorInfo.GetParameters()
                                                 .Select(
                                x =>
                                resolvedDependencies[new IxIdentifier(x.ParameterType)]
                                .Object)
                                                 .ToArray();

                            object instanceObj = constructorInfo.Invoke(arguments);

                            Critical.Assert(
                                instanceObj != null,
                                "Constructor call through reflection should not return null.");

                            lock (instance.ProviderNode.Host.InstanceTreeSyncRoot)
                            {
                                foreach (KeyValuePair <IxIdentifier, IIxInstance> kvp
                                         in resolvedDependencies)
                                {
                                    // ReSharper disable once ObjectCreationAsStatement
                                    new IxReferenceLock(kvp.Value, instance);
                                }
                            }

                            // Just to avoid multiple functions.
                            return instanceObj;
                        }
                        catch (TargetInvocationException ex)
                        {
                            throw ex.InnerException;
                        }
                    }),
                        configTypeInfo.GenericTypeArguments[0]);
                }

                return next(factoryConfig);
            });
        }
        private InstanceFactoryBuilderDelegate DelegateInstanceBuilder(
            InstanceFactoryBuilderDelegate next)
        {
            return(instanceBuilderConfig =>
            {
                TypeInfo configTypeInfo = instanceBuilderConfig.GetType().GetTypeInfo();

                var delegateInstanceBuilderConfig = instanceBuilderConfig as IxDelegateInstanceBuilderConfig;
                if (delegateInstanceBuilderConfig == null)
                {
                    return next(instanceBuilderConfig);
                }

                TypeInfo delegateType = delegateInstanceBuilderConfig.Func.GetType().GetTypeInfo();

                MethodInfo methodInfo = delegateType.GetDeclaredMethod("Invoke");

                HashSet <IxIdentifier> dependencies =
                    methodInfo.GetParameters().Select(x => new IxIdentifier(x.ParameterType)).ToHashSet();
                if (dependencies.Count != methodInfo.GetParameters().Length)
                {
                    throw new IxConfigurationException(
                        "Multiple parameters with the same type not supported by IxClassRawFactory.");
                }

                // TODO: Add tests for this feature
                List <RequireAttribute> requireAttributes =
                    methodInfo.GetCustomAttributes <RequireAttribute>().ToList();
                foreach (RequireAttribute requireAttribute in requireAttributes)
                {
                    if (!dependencies.Add(new IxIdentifier(requireAttribute.Type)))
                    {
                        throw new IxConfigurationException(
                            "Multiple parameters with the same type not supported by IxClassRawFactory.");
                    }
                }

                return new IxInstanceFactory(
                    (instance, parentInstance, resolveContext, frame) => ResolveList(
                        instance,
                        dependencies,
                        resolveContext,
                        frame,
                        async resolvedDependencies =>
                {
                    object[] arguments = methodInfo.GetParameters()
                                         .Select(
                        x =>
                        resolvedDependencies[new IxIdentifier(x.ParameterType)].Object)
                                         .ToArray();

                    object instanceObjTask;
                    Task instanceObjTaskCasted;
                    try
                    {
                        // TODO: Optimize me.
                        instanceObjTask = methodInfo.Invoke(
                            delegateInstanceBuilderConfig.Func,
                            arguments);
                        instanceObjTaskCasted = (Task)instanceObjTask.GetType().GetTypeInfo()
                                                .GetDeclaredMethod("AsTask")
                                                .Invoke(instanceObjTask, new object[] { });
                        await instanceObjTaskCasted;
                    }
                    catch (TargetInvocationException ex)
                    {
                        throw ex.InnerException;
                    }

                    object instanceObj = instanceObjTaskCasted.GetResult();

                    // TODO: TryCast,
                    // TODO: Allow null result.
                    Critical.Assert(
                        instanceObj != null,
                        "Constructor call through reflection should not return null.");

                    lock (instance.ProviderNode.Host.InstanceTreeSyncRoot)
                    {
                        foreach (KeyValuePair <IxIdentifier, IIxInstance> kvp
                                 in resolvedDependencies)
                        {
                            // ReSharper disable once ObjectCreationAsStatement
                            new IxReferenceLock(kvp.Value, instance);
                        }
                    }

                    return instanceObj;
                }),
                    methodInfo.ReturnType.GenericTypeArguments[0]);
            });
        }
Example #28
0
 void IIxInstance.RemoveOwnedLock(IIxInstanceLock instanceLock)
 {
     Critical.Assert(false, "This is completely virtual object and cannot own locks.");
 }
Example #29
0
 void IIxInstance.SetData(IxProviderNode providerNode, [CanBeNull] object data)
 {
     Critical.Assert(false, "This object not intended to have children and children data.");
 }
Example #30
0
 protected void EnsureTreeLocked()
 {
     Critical.Assert(
         Monitor.IsEntered(ProviderNode.Host.InstanceTreeSyncRoot),
         "Lock related operation should be performed under global tree lock.");
 }