public void Compose(CompositionBatch batch)
        {
            this.ThrowIfDisposed();
            this.EnsureRunning();

            Requires.NotNull(batch, "batch");

            // Quick exit test can be done prior to cloning since it's just an optimization, not a
            // change in behavior
            if ((batch.PartsToAdd.Count == 0) && (batch.PartsToRemove.Count == 0))
            {
                return;
            }

            CompositionResult result = CompositionResult.SucceededResult;

            // Clone the batch, so that the external changes wouldn't happen half-way thorugh compose
            // NOTE : this does not guarantee the atomicity of cloning, which is not the goal anyway,
            // rather the fact that all subsequent calls will deal with an unchanging batch
            batch = new CompositionBatch(batch.PartsToAdd, batch.PartsToRemove);

            var newParts = GetUpdatedPartsList(batch);

            // Allow only recursive calls from the import engine to see the changes until
            // they've been verified ...
            using (var atomicComposition = new AtomicComposition())
            {
                // Don't allow reentrant calls to compose during previewing to prevent
                // corrupted state.
                if (this._currentlyComposing)
                {
                    throw new InvalidOperationException(Strings.ReentrantCompose);
                }

                this._currentlyComposing = true;

                try
                {
                    // In the meantime recursive calls need to be able to see the list as well
                    atomicComposition.SetValue(this, newParts);

                    // Recompose any existing imports effected by the these changes first so that
                    // adapters, resurrected parts, etc. can all play their role in satisfying
                    // imports for added parts
                    this.Recompose(batch, atomicComposition);

                    // Ensure that required imports can be satisfied
                    foreach (ComposablePart part in batch.PartsToAdd)
                    {
                        // collect the result of previewing all the adds in the batch
                        try
                        {
                            this._importEngine.PreviewImports(part, atomicComposition);
                        }
                        catch (ChangeRejectedException ex)
                        {
                            result = result.MergeResult(new CompositionResult(ex.Errors));
                        }
                    }

                    result.ThrowOnErrors(atomicComposition);

                    // Complete the new parts since they passed previewing.`
                    using (this._lock.LockStateForWrite())
                    {
                        this._parts = newParts;
                    }

                    atomicComposition.Complete();
                }
                finally
                {
                    this._currentlyComposing = false;
                }
            }

            // Satisfy Imports
            // - Satisfy imports on all newly added component parts
            foreach (ComposablePart part in batch.PartsToAdd)
            {
                result = result.MergeResult(CompositionServices.TryInvoke(() =>
                                                                          this._importEngine.SatisfyImports(part)));
            }

            // return errors
            result.ThrowOnErrors();
        }
        private static CompositionResult <IEnumerable <Export> > TryGetExports(ExportProvider provider,
                                                                               ComposablePart part, ImportDefinition definition, AtomicComposition atomicComposition)
        {
            try
            {
                var exports = provider.GetExports(definition, atomicComposition).AsArray();
                return(new CompositionResult <IEnumerable <Export> >(exports));
            }
            catch (ImportCardinalityMismatchException ex)
            {
                // Either not enough or too many exports that match the definition
                CompositionException exception = new CompositionException(ErrorBuilder.CreateImportCardinalityMismatch(ex, definition));

                return(new CompositionResult <IEnumerable <Export> >(
                           ErrorBuilder.CreatePartCannotSetImport(part, definition, exception)));
            }
        }
Пример #3
0
        public void Compose(CompositionBatch batch)
        {
            ThrowIfDisposed();
            EnsureRunning();

            Requires.NotNull(batch, nameof(batch));

            // Quick exit test can be done prior to cloning since it's just an optimization, not a
            // change in behavior
            if ((batch.PartsToAdd.Count == 0) && (batch.PartsToRemove.Count == 0))
            {
                return;
            }

            CompositionResult result = CompositionResult.SucceededResult;

            // Get updated parts list and a cloned batch
            var newParts = GetUpdatedPartsList(ref batch);

            // Allow only recursive calls from the import engine to see the changes until
            // they've been verified ...
            using (var atomicComposition = new AtomicComposition())
            {
                // Don't allow reentrant calls to compose during previewing to prevent
                // corrupted state.
                if (_currentlyComposing)
                {
                    throw new InvalidOperationException(SR.ReentrantCompose);
                }

                _currentlyComposing = true;

                try
                {
                    // In the meantime recursive calls need to be able to see the list as well
                    atomicComposition.SetValue(this, newParts);

                    // Recompose any existing imports effected by the these changes first so that
                    // adapters, resurrected parts, etc. can all play their role in satisfying
                    // imports for added parts
                    Recompose(batch, atomicComposition);

                    // Ensure that required imports can be satisfied
                    foreach (ComposablePart part in batch.PartsToAdd)
                    {
                        // collect the result of previewing all the adds in the batch
                        try
                        {
                            ImportEngine.PreviewImports(part, atomicComposition);
                        }
                        catch (ChangeRejectedException ex)
                        {
                            result = result.MergeResult(new CompositionResult(ex.Errors));
                        }
                    }

                    result.ThrowOnErrors(atomicComposition);

                    // Complete the new parts since they passed previewing.`
                    using (_lock.LockStateForWrite())
                    {
                        _parts = newParts;
                    }

                    atomicComposition.Complete();
                }
                finally
                {
                    _currentlyComposing = false;
                }
            }

            // Satisfy Imports
            // - Satisfy imports on all newly added component parts
            foreach (ComposablePart part in batch.PartsToAdd)
            {
                result = result.MergeResult(CompositionServices.TryInvoke(() =>
                                                                          ImportEngine.SatisfyImports(part)));
            }

            // return errors
            result.ThrowOnErrors();
        }
        public bool TryGetExports(System.ComponentModel.Composition.Primitives.ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable <System.ComponentModel.Composition.Primitives.Export> exports)
        {
            exports = default(IEnumerable <System.ComponentModel.Composition.Primitives.Export>);

            return(default(bool));
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref="ComposablePartCatalogChangeEventArgs"/>.
        /// </summary>
        /// <param name="addedDefinitions">
        ///     An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartDefinition"/> objects that
        ///     are being added to the <see cref="ComposablePartCatalog"/>.
        /// </param>
        /// <param name="removedDefinitions">
        ///     An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartDefinition"/> objects that
        ///     are being removed from the <see cref="ComposablePartCatalog"/>.
        /// </param>
        /// <param name="atomicComposition">
        ///     A <see cref="AtomicComposition"/> representing all tentative changes that will
        ///     be completed if the change is successful, or discarded if it is not.
        ///     <see langword="null"/> if being applied outside a <see cref="AtomicComposition"/>
        ///     or during a <see cref="INotifyComposablePartCatalogChanged.Changed"/> event.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="addedDefinitions"/> or <paramref name="removedDefinitions"/> is <see langword="null"/>.
        /// </exception>
        public ComposablePartCatalogChangeEventArgs(IEnumerable <ComposablePartDefinition> addedDefinitions,
                                                    IEnumerable <ComposablePartDefinition> removedDefinitions, AtomicComposition atomicComposition)
        {
            Requires.NotNull(addedDefinitions, "addedDefinitions");
            Requires.NotNull(removedDefinitions, "removedDefinitions");

            this.AddedDefinitions   = addedDefinitions.AsArray();
            this.RemovedDefinitions = removedDefinitions.AsArray();
            this.AtomicComposition  = atomicComposition;
        }
Пример #6
0
        private void TestNoValue(AtomicComposition context, object key)
        {
            string value;

            Assert.IsFalse(context.TryGetValue(key, out value));
        }
 public IEnumerable <System.ComponentModel.Composition.Primitives.Export> GetExports(System.ComponentModel.Composition.Primitives.ImportDefinition definition, AtomicComposition atomicComposition)
 {
     return(default(IEnumerable <System.ComponentModel.Composition.Primitives.Export>));
 }
Пример #8
0
        /// <summary>
        /// Returns all exports that match the conditions of the specified import.
        /// </summary>
        /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the
        /// <see cref="Export"/> to get.</param>
        /// <returns></returns>
        /// <result>
        /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match
        /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an
        /// empty <see cref="IEnumerable{T}"/>.
        /// </result>
        /// <remarks>
        ///     <note type="inheritinfo">
        /// The implementers should not treat the cardinality-related mismatches as errors, and are not
        /// expected to throw exceptions in those cases.
        /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one,
        /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>.
        /// </note>
        /// </remarks>
        protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
        {
            ThrowIfDisposed();
            EnsureRunning();

            if (_innerExportProvider == null)
            {
                throw new Exception(SR.Diagnostic_InternalExceptionMessage);
            }

            IEnumerable <Export> exports;

            _innerExportProvider.TryGetExports(definition, atomicComposition, out exports);
            return(exports);
        }
Пример #9
0
        private IEnumerable <Export> InternalGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
        {
            ThrowIfDisposed();
            EnsureRunning();

            // Use the version of the catalog appropriate to this atomicComposition
            ComposablePartCatalog currentCatalog = atomicComposition.GetValueAllowNull(_catalog);

            IPartCreatorImportDefinition partCreatorDefinition = definition as IPartCreatorImportDefinition;
            bool isExportFactory = false;

            if (partCreatorDefinition != null)
            {
                definition      = partCreatorDefinition.ProductImportDefinition;
                isExportFactory = true;
            }

            CreationPolicy importPolicy = definition.GetRequiredCreationPolicy();

            List <Export> exports         = new List <Export>();
            bool          ensureRejection = EnsureRejection(atomicComposition);

            foreach (var partDefinitionAndExportDefinition in currentCatalog.GetExports(definition))
            {
                bool isPartRejected = ensureRejection && IsRejected(partDefinitionAndExportDefinition.Item1, atomicComposition);
                if (!isPartRejected)
                {
                    exports.Add(CreateExport(partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2, isExportFactory, importPolicy));
                }
            }

            return(exports);
        }
Пример #10
0
        /// <summary>
        /// Returns all exports that match the conditions of the specified import.
        /// </summary>
        /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the
        /// <see cref="Export"/> to get.</param>
        /// <returns></returns>
        /// <result>
        /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match
        /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an
        /// empty <see cref="IEnumerable{T}"/>.
        /// </result>
        /// <remarks>
        ///     <note type="inheritinfo">
        /// The implementers should not treat the cardinality-related mismatches as errors, and are not
        /// expected to throw exceptions in those cases.
        /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one,
        /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>.
        /// </note>
        /// </remarks>
        protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
        {
            this.ThrowIfDisposed();
            this.EnsureRunning();

            Assumes.NotNull(this._innerExportProvider);

            IEnumerable <Export> exports;

            this._innerExportProvider.TryGetExports(definition, atomicComposition, out exports);
            return(exports);
        }
Пример #11
0
        internal static T GetValueAllowNull <T>(this AtomicComposition atomicComposition, T defaultResultAndKey) where T : class
        {
            Assumes.NotNull(defaultResultAndKey);

            return(GetValueAllowNull <T>(atomicComposition, defaultResultAndKey, defaultResultAndKey));
        }
Пример #12
0
 protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
 {
     Assumes.NotNull(this._getExportsCore);
     return(this._getExportsCore(definition, atomicComposition));
 }
Пример #13
0
        /// <summary>
        /// Returns all exports that match the conditions of the specified import.
        /// </summary>
        /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the
        /// <see cref="Export"/> to get.</param>
        /// <returns></returns>
        /// <result>
        /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match
        /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an
        /// empty <see cref="IEnumerable{T}"/>.
        /// </result>
        /// <remarks>
        ///     <note type="inheritinfo">
        /// The implementers should not treat the cardinality-related mismatches as errors, and are not
        /// expected to throw exceptions in those cases.
        /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one,
        /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>.
        /// </note>
        /// </remarks>
        protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
        {
            this.ThrowIfDisposed();

            IEnumerable <Export> exports = null;

            this._rootProvider.TryGetExports(definition, atomicComposition, out exports);

            return(exports);
        }
Пример #14
0
        /// <summary>
        /// Returns all exports that match the conditions of the specified import.
        /// </summary>
        /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the
        /// <see cref="Export"/> to get.</param>
        /// <returns></returns>
        /// <result>
        /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match
        /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an
        /// empty <see cref="IEnumerable{T}"/>.
        /// </result>
        /// <remarks>
        ///     <note type="inheritinfo">
        /// The implementers should not treat the cardinality-related mismatches as errors, and are not
        /// expected to throw exceptions in those cases.
        /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one,
        /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>.
        /// </note>
        /// </remarks>
        protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
        {
            ThrowIfDisposed();

            IEnumerable <Export> exports = null;

            object source;

            if (!definition.Metadata.TryGetValue(CompositionConstants.ImportSourceMetadataName, out source))
            {
                source = ImportSource.Any;
            }

            switch ((ImportSource)source)
            {
            case ImportSource.Any:
                Assumes.NotNull(_rootProvider);
                _rootProvider.TryGetExports(definition, atomicComposition, out exports);
                break;

            case ImportSource.Local:
                Assumes.NotNull(_localExportProvider);
                _localExportProvider.TryGetExports(definition.RemoveImportSource(), atomicComposition, out exports);
                break;

            case ImportSource.NonLocal:
                if (_ancestorExportProvider != null)
                {
                    _ancestorExportProvider.TryGetExports(definition.RemoveImportSource(), atomicComposition, out exports);
                }
                break;
            }

            return(exports);
        }
Пример #15
0
            protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
            {
                List <Export> exports = new List <Export>();

                ImportDefinition queryImport = TranslateImport(definition);

                if (queryImport == null)
                {
                    return(exports);
                }

                // go through the catalogs and see if there's anything there of interest
                foreach (CompositionScopeDefinition childCatalog in this._scopeDefinition.Children)
                {
                    foreach (var partDefinitionAndExportDefinition in childCatalog.GetExportsFromPublicSurface(queryImport))
                    {
                        using (var container = this.CreateChildContainer(childCatalog))
                        {
                            // We create a nested AtomicComposition() because the container will be Disposed and
                            // the RevertActions need to operate before we Dispose the child container
                            using (var ac = new AtomicComposition(atomicComposition))
                            {
                                var childCatalogExportProvider = container.CatalogExportProvider;
                                if (!childCatalogExportProvider.DetermineRejection(partDefinitionAndExportDefinition.Item1, ac))
                                {
                                    exports.Add(this.CreateScopeExport(childCatalog, partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2));
                                }
                            }
                        }
                    }
                }

                return(exports);
            }
Пример #16
0
 protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
 {
     return(_outerExportProvider.InternalGetExportsCore(definition, atomicComposition));
 }
Пример #17
0
 public void Constructor1()
 {
     var ct = new AtomicComposition();
 }
Пример #18
0
        private void DisposePart(object exportedValue, CatalogPart catalogPart, AtomicComposition atomicComposition)
        {
            if (catalogPart == null)
            {
                throw new ArgumentNullException(nameof(catalogPart));
            }

            if (_isDisposed)
            {
                return;
            }

            ImportEngine importEngine = null;

            using (_lock.LockStateForWrite())
            {
                if (_isDisposed)
                {
                    return;
                }

                importEngine = _importEngine;
            }
            if (importEngine != null)
            {
                importEngine.ReleaseImports(catalogPart.Part, atomicComposition);
            }
            if (exportedValue != null)
            {
                atomicComposition.AddCompleteActionAllowNull(() =>
                {
                    AllowPartCollection(exportedValue);
                });
            }

            IDisposable diposablePart = catalogPart.Part as IDisposable;

            if (diposablePart != null)
            {
                atomicComposition.AddCompleteActionAllowNull(() =>
                {
                    bool removed = false;

                    if (_isDisposed)
                    {
                        return;
                    }
                    using (_lock.LockStateForWrite())
                    {
                        if (_isDisposed)
                        {
                            return;
                        }

                        removed = _partsToDispose.Remove(diposablePart);
                    }

                    if (removed)
                    {
                        diposablePart.Dispose();
                    }
                });
            }
        }
Пример #19
0
        public void AtomicComposition_NestedQueries()
        {
            // This is a rather convoluted test that exercises the way AtomicComposition used to work to
            // ensure consistency of the newer design
            var key = new Object();

            using (var contextA = new AtomicComposition())
            {
                SetQuery(contextA, key, (int parameter, Func <int, bool> parentQuery) =>
                {
                    if (parameter == 22)
                    {
                        return(true);
                    }
                    if (parentQuery != null)
                    {
                        return(parentQuery(parameter));
                    }
                    return(false);
                });
                TestQuery(contextA, key, 22, true);

                using (var contextB = new AtomicComposition(contextA))
                {
                    TestQuery(contextB, key, 22, true);
                    SetQuery(contextB, key, (int parameter, Func <int, bool> parentQuery) =>
                    {
                        if (parentQuery != null)
                        {
                            return(!parentQuery(parameter));
                        }
                        Assert.Fail(); // Should never have no parent
                        return(false);
                    });
                    TestQuery(contextB, key, 21, true);
                    TestQuery(contextB, key, 22, false);

                    using (var contextC = new AtomicComposition(contextB))
                    {
                        SetQuery(contextC, key, (int parameter, Func <int, bool> parentQuery) =>
                        {
                            if (parameter == 23)
                            {
                                return(true);
                            }
                            if (parentQuery != null)
                            {
                                return(!parentQuery(parameter));
                            }
                            Assert.Fail(); // Should never have no parent
                            return(false);
                        });
                        TestQuery(contextC, key, 21, false);
                        TestQuery(contextC, key, 22, true);
                        TestQuery(contextC, key, 23, true);
                        contextC.Complete();
                    }

                    using (var contextD = new AtomicComposition(contextB))
                    {
                        SetQuery(contextD, key, (int parameter, Func <int, bool> parentQuery) =>
                        {
                            if (parentQuery != null)
                            {
                                return(parentQuery(parameter + 1));
                            }
                            Assert.Fail(); // Should never have no parent
                            return(false);
                        });
                        TestQuery(contextD, key, 21, true);
                        TestQuery(contextD, key, 22, true);
                        TestQuery(contextD, key, 23, false);
                        // No complete
                    }

                    contextB.Complete();
                }
                TestQuery(contextA, key, 21, false);
                TestQuery(contextA, key, 22, true);
                TestQuery(contextA, key, 23, true);
                contextA.Complete();
            }
        }
Пример #20
0
 private bool EnsureRejection(AtomicComposition atomicComposition)
 {
     return(!(_disableSilentRejection && (atomicComposition == null)));
 }
 protected abstract IEnumerable <System.ComponentModel.Composition.Primitives.Export> GetExportsCore(System.ComponentModel.Composition.Primitives.ImportDefinition definition, AtomicComposition atomicComposition);
Пример #22
0
        /// <summary>
        /// Returns all exports that match the conditions of the specified import.
        /// </summary>
        /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the
        /// <see cref="Export"/> to get.</param>
        /// <returns></returns>
        /// <result>
        /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match
        /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an
        /// empty <see cref="IEnumerable{T}"/>.
        /// </result>
        /// <remarks>
        ///     <note type="inheritinfo">
        /// The implementers should not treat the cardinality-related mismatches as errors, and are not
        /// expected to throw exceptions in those cases.
        /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one,
        /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>.
        /// </note>
        /// </remarks>
        protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
        {
            this.ThrowIfDisposed();
            this.EnsureRunning();

            // Use the version of the catalog appropriate to this atomicComposition
            ComposablePartCatalog currentCatalog = atomicComposition.GetValueAllowNull(this._catalog);

            IPartCreatorImportDefinition partCreatorDefinition = definition as IPartCreatorImportDefinition;
            bool isPartCreator = false;

            if (partCreatorDefinition != null)
            {
                definition    = partCreatorDefinition.ProductImportDefinition;
                isPartCreator = true;
            }

            CreationPolicy importPolicy = definition.GetRequiredCreationPolicy();

            List <Export> exports = new List <Export>();

            foreach (var partDefinitionAndExportDefinition in currentCatalog.GetExports(definition))
            {
                if (!IsRejected(partDefinitionAndExportDefinition.Item1, atomicComposition))
                {
                    if (isPartCreator)
                    {
                        exports.Add(new PartCreatorExport(this,
                                                          partDefinitionAndExportDefinition.Item1,
                                                          partDefinitionAndExportDefinition.Item2));
                    }
                    else
                    {
                        exports.Add(CatalogExport.CreateExport(this,
                                                               partDefinitionAndExportDefinition.Item1,
                                                               partDefinitionAndExportDefinition.Item2,
                                                               importPolicy));
                    }
                }
            }

            return(exports);
        }
            protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
            {
                List <Export> exports = new List <Export>();

                ImportDefinition queryImport = TranslateImport(definition);

                if (queryImport == null)
                {
                    return(exports);
                }

                // go through the catalogs and see if there's anything there of interest
                foreach (CompositionScopeDefinition childCatalog in _scopeDefinition.Children)
                {
                    foreach (var partDefinitionAndExportDefinition in childCatalog.GetExportsFromPublicSurface(queryImport))
                    {
                        // We found a match in the child catalog. Now we need to check that it doesn't get rejected.
                        // if the rejetecion is enabled and atomic composition is present, we will actually have to do the work, if not - we just use what we have
                        bool isChildPartRejected = false;

                        if (_catalogExportProvider.EnsureRejection(atomicComposition))
                        {
                            using (var container = CreateChildContainer(childCatalog))
                            {
                                // We create a nested AtomicComposition() because the container will be Disposed and
                                // the RevertActions need to operate before we Dispose the child container
                                using (var localAtomicComposition = new AtomicComposition(atomicComposition))
                                {
                                    isChildPartRejected = container.CatalogExportProvider.DetermineRejection(partDefinitionAndExportDefinition.Item1, localAtomicComposition);
                                }
                            }
                        }

                        // If the child part has not been rejected, we will add it to the result set.
                        if (!isChildPartRejected)
                        {
                            exports.Add(CreateScopeExport(childCatalog, partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2));
                        }
                    }
                }

                return(exports);
            }
Пример #24
0
        private bool DetermineRejection(ComposablePartDefinition definition, AtomicComposition parentAtomicComposition)
        {
            ChangeRejectedException exception = null;

            using (var localAtomicComposition = new AtomicComposition(parentAtomicComposition))
            {
                // The part definition we're currently working on is treated optimistically
                // as if we know it hasn't been rejected.  This handles recursion, and if we
                // later decide that it has been rejected we'll discard all nested progress so
                // all side-effects of the mistake are erased.
                //
                // Note that this means that recursive failures that would be detected by the
                // import engine are not discovered by rejection currently.  Loops among
                // prerequisites, runaway import chains involving factories, and prerequisites
                // that cannot be fully satisfied still result in runtime errors.  Doing
                // otherwise would be possible but potentially expensive - and could be a v2
                // improvement if deemed worthwhile.
                UpdateAtomicCompositionQuery(localAtomicComposition,
                                             def => definition.Equals(def), AtomicCompositionQueryState.TreatAsValidated);

                var newPart = definition.CreatePart();
                try
                {
                    this._importEngine.PreviewImports(newPart, localAtomicComposition);

                    // Reuse the partially-fleshed out part the next time we need a shared
                    // instance to keep the expense of pre-validation to a minimum.  Note that
                    // _activatedParts holds references to both shared and non-shared parts.
                    // The non-shared parts will only be used for rejection purposes only but
                    // the shared parts will be handed out when requested via GetExports as
                    // well as be used for rejection purposes.
                    localAtomicComposition.AddCompleteActionAllowNull(() =>
                    {
                        using (this._lock.LockStateForWrite())
                        {
                            if (!this._activatedParts.ContainsKey(definition))
                            {
                                this._activatedParts.Add(definition, newPart);
                                IDisposable newDisposablePart = newPart as IDisposable;
                                if (newDisposablePart != null)
                                {
                                    this._partsToDispose.Add(newDisposablePart);
                                }
                            }
                        }
                    });

                    // Success! Complete any recursive work that was conditioned on this part's validation
                    localAtomicComposition.Complete();

                    return(false);
                }
                catch (ChangeRejectedException ex)
                {
                    exception = ex;
                }
            }

            // If we've reached this point then this part has been rejected so we need to
            // record the rejection in our parent composition or execute it immediately if
            // one doesn't exist.
            parentAtomicComposition.AddCompleteActionAllowNull(() =>
            {
                using (this._lock.LockStateForWrite())
                {
                    this._rejectedParts.Add(definition);
                }

                CompositionTrace.PartDefinitionRejected(definition, exception);
            });
            if (parentAtomicComposition != null)
            {
                UpdateAtomicCompositionQuery(parentAtomicComposition,
                                             def => definition.Equals(def), AtomicCompositionQueryState.TreatAsRejected);
            }

            return(true);
        }
        private CompositionResult TryRecomposeImports(PartManager partManager,
                                                      IEnumerable <ExportDefinition> changedExports, AtomicComposition atomicComposition)
        {
            var result = CompositionResult.SucceededResult;

            switch (partManager.State)
            {
            case ImportState.ImportsPreviewed:
            case ImportState.Composed:
                // Validate states to continue.
                break;

            default:
            {
                // All other states are invalid and for recomposition.
                return(new CompositionResult(ErrorBuilder.InvalidStateForRecompposition(partManager.Part)));
            }
            }

            var  affectedImports = RecompositionManager.GetAffectedImports(partManager.Part, changedExports);
            bool partComposed    = (partManager.State == ImportState.Composed);

            bool recomposedImport = false;

            foreach (var import in affectedImports)
            {
                result = result.MergeResult(
                    TryRecomposeImport(partManager, partComposed, import, atomicComposition));

                recomposedImport = true;
            }

            // Knowing that the part has already been composed before and that the only possible
            // changes are to recomposable imports, we can safely go ahead and do this now or
            // schedule it for later
            if (result.Succeeded && recomposedImport && partComposed)
            {
                if (atomicComposition == null)
                {
                    result = result.MergeResult(partManager.TryOnComposed());
                }
                else
                {
                    atomicComposition.AddCompleteAction(() => partManager.TryOnComposed().ThrowOnErrors());
                }
            }

            return(result);
        }
Пример #26
0
        private void UpdateRejections(IEnumerable <ExportDefinition> changedExports, AtomicComposition atomicComposition)
        {
            using (var localAtomicComposition = new AtomicComposition(atomicComposition))
            {
                // Reconsider every part definition that has been previously
                // rejected to see if any of them can be added back.
                var affectedRejections     = new HashSet <ComposablePartDefinition>();
                var atomicCompositionQuery = GetAtomicCompositionQuery(localAtomicComposition);

                ComposablePartDefinition[] rejectedParts;
                using (this._lock.LockStateForRead())
                {
                    rejectedParts = this._rejectedParts.ToArray();
                }
                foreach (var definition in rejectedParts)
                {
                    if (atomicCompositionQuery(definition) == AtomicCompositionQueryState.TreatAsValidated)
                    {
                        continue;
                    }

                    foreach (var import in definition.ImportDefinitions.Where(ImportEngine.IsRequiredImportForPreview))
                    {
                        if (changedExports.Any(export => import.IsConstraintSatisfiedBy(export)))
                        {
                            affectedRejections.Add(definition);
                            break;
                        }
                    }
                }
                UpdateAtomicCompositionQuery(localAtomicComposition,
                                             def => affectedRejections.Contains(def), AtomicCompositionQueryState.NeedsTesting);

                // Determine if any of the resurrectable parts is now available so that we can
                // notify listeners of the exact changes to exports
                var resurrectedExports = new List <ExportDefinition>();

                foreach (var partDefinition in affectedRejections)
                {
                    if (!IsRejected(partDefinition, localAtomicComposition))
                    {
                        // Notify listeners of the newly available exports and
                        // prepare to remove the rejected part from the list of rejections
                        resurrectedExports.AddRange(partDefinition.ExportDefinitions);

                        // Capture the local so that the closure below refers to the current definition
                        // in the loop and not the value of 'partDefinition' when the closure executes
                        var capturedPartDefinition = partDefinition;
                        localAtomicComposition.AddCompleteAction(() =>
                        {
                            using (this._lock.LockStateForWrite())
                            {
                                this._rejectedParts.Remove(capturedPartDefinition);
                            }

                            CompositionTrace.PartDefinitionResurrected(capturedPartDefinition);
                        });
                    }
                }

                // Notify anyone sourcing exports that the resurrected exports have appeared
                if (resurrectedExports.Any())
                {
                    this.OnExportsChanging(
                        new ExportsChangeEventArgs(resurrectedExports, new ExportDefinition[0], localAtomicComposition));

                    localAtomicComposition.AddCompleteAction(() => this.OnExportsChanged(
                                                                 new ExportsChangeEventArgs(resurrectedExports, new ExportDefinition[0], null)));
                }

                localAtomicComposition.Complete();
            }
        }
/// <summary>
        /// Returns all exports that match the conditions of the specified import.
        /// </summary>
        /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the
        /// <see cref="Export"/> to get.</param>
        /// <returns></returns>
        /// <result>
        /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match
        /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an
        /// empty <see cref="IEnumerable{T}"/>.
        /// </result>
        /// <remarks>
        ///     <note type="inheritinfo">
        /// The implementers should not treat the cardinality-related mismatches as errors, and are not
        /// expected to throw exceptions in those cases.
        /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one,
        /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>.
        /// </note>
        /// </remarks>
        protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
        {
            ThrowIfDisposed();
            EnsureRunning();

            // Determine whether there is a composition atomicComposition-specific list of parts to use,
            // failing that use the usual list.  We never change the list of parts in place,
            // but rather copy, change and write a new list atomically.  Therefore all we need
            // to do here is to read the _parts member.
            List <ComposablePart> parts = null;

            using (_lock.LockStateForRead())
            {
                parts = atomicComposition.GetValueAllowNull(this, _parts);
            }

            if (parts.Count == 0)
            {
                return(null);
            }

            List <Export> exports = new List <Export>();

            foreach (var part in parts)
            {
                foreach (var exportDefinition in part.ExportDefinitions)
                {
                    if (definition.IsConstraintSatisfiedBy(exportDefinition))
                    {
                        exports.Add(CreateExport(part, exportDefinition));
                    }
                }
            }
            return(exports);
        }
Пример #28
0
        private Func <ComposablePartDefinition, AtomicCompositionQueryState> GetAtomicCompositionQuery(AtomicComposition atomicComposition)
        {
            Func <ComposablePartDefinition, AtomicCompositionQueryState> atomicCompositionQuery;

            atomicComposition.TryGetValue(this, out atomicCompositionQuery);

            if (atomicCompositionQuery == null)
            {
                return((definition) => AtomicCompositionQueryState.Unknown);
            }

            return(atomicCompositionQuery);
        }
Пример #29
0
        private CompositionResult TrySatisfyImportSubset(PartManager partManager,
                                                         IEnumerable <ImportDefinition> imports, AtomicComposition atomicComposition)
        {
            CompositionResult result = CompositionResult.SucceededResult;

            var part = partManager.Part;

            foreach (ImportDefinition import in imports)
            {
                var exports = partManager.GetSavedImport(import);

                if (exports == null)
                {
                    CompositionResult <IEnumerable <Export> > exportsResult = TryGetExports(
                        _sourceProvider, part, import, atomicComposition);

                    if (!exportsResult.Succeeded)
                    {
                        result = result.MergeResult(exportsResult.ToResult());
                        continue;
                    }
                    exports = exportsResult.Value.AsArray();
                }

                if (atomicComposition == null)
                {
                    result = result.MergeResult(
                        partManager.TrySetImport(import, exports));
                }
                else
                {
                    partManager.SetSavedImport(import, exports, atomicComposition);
                }
            }
            return(result);
        }
 protected override IEnumerable <System.ComponentModel.Composition.Primitives.Export> GetExportsCore(System.ComponentModel.Composition.Primitives.ImportDefinition definition, AtomicComposition atomicComposition)
 {
     return(default(IEnumerable <System.ComponentModel.Composition.Primitives.Export>));
 }