Click here to Skip to main content
15,886,362 members
Articles / DevOps / Testing

Composite Application Reloaded

Rate me:
Please Sign up or sign in to vote.
4.88/5 (38 votes)
11 May 2011CPOL12 min read 117.8K   1.5K   95  
A much simpler composite application library.
// -----------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Primitives;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Threading;
using Microsoft.Internal;
using Microsoft.Internal.Collections;

namespace System.ComponentModel.Composition.Hosting
{
    public partial class FilteredCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
    {
        private Func<ComposablePartDefinition, bool> _filter;
        private ComposablePartCatalog _innerCatalog;
        private IEnumerable<ComposablePartDefinition> _partsQuery;
        private FilteredCatalog _complement;
        private object _lock = new object();
        private volatile bool _isDisposed = false;

        /// <summary>
        /// Initializes a new instance of the <see cref="FilteredCatalog"/> class.
        /// </summary>
        /// <param name="catalog">The catalog.</param>
        /// <param name="filter">The filter.</param>
        public FilteredCatalog(ComposablePartCatalog catalog, Func<ComposablePartDefinition, bool> filter) : 
            this(catalog, filter, null)
        {
        }

        internal FilteredCatalog(ComposablePartCatalog catalog, Func<ComposablePartDefinition, bool> filter, FilteredCatalog complement)
        {
            Requires.NotNull(catalog, "catalog");
            Requires.NotNull(filter, "filter");

            this._innerCatalog = catalog;
            this._filter = filter;
            this._complement = complement;
            this._partsQuery = this._innerCatalog.Parts.Where(this._filter);

            INotifyComposablePartCatalogChanged notifyCatalog = this._innerCatalog as INotifyComposablePartCatalogChanged;
            if (notifyCatalog != null)
            {
                notifyCatalog.Changed += this.OnChangedInternal;
                notifyCatalog.Changing += this.OnChangingInternal;
            }
        }


        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    if(!this._isDisposed)
                    {
                        INotifyComposablePartCatalogChanged notifyCatalog = null;
                        try
                        {
                            lock (this._lock)
                            {
                                if (!this._isDisposed)
                                {
                                    this._isDisposed = true;
                                    notifyCatalog = this._innerCatalog as INotifyComposablePartCatalogChanged;
                                    this._innerCatalog = null;
                                }
                            }
                        }
                        finally
                        {
                            if (notifyCatalog != null)
                            {
                                notifyCatalog.Changed -= this.OnChangedInternal;
                                notifyCatalog.Changing -= this.OnChangingInternal;
                            }
                        }
                    }
                }
            }
            finally
            {
                base.Dispose(disposing);
            }
        }

        /// <summary>
        /// Gets the part definitions of the catalog.
        /// </summary>
        /// <value>
        /// A <see cref="IEnumerable{T}"/> of <see cref="ComposablePartDefinition"/> objects of the
        /// <see cref="ComposablePartCatalog"/>.
        /// </value>
        /// <exception cref="ObjectDisposedException">
        /// The <see cref="ComposablePartCatalog"/> has been disposed of.
        /// </exception>
        /// <remarks>
        /// 	<note type="inheritinfo">
        /// Overriders of this property should never return <see langword="null"/>.
        /// </note>
        /// </remarks>
        public override IEnumerable<ComposablePartDefinition> Parts
        {
            get
            {
                this.ThrowIfDisposed();

                return this._partsQuery;
            }
        }

        /// <summary>
        /// Gets the complement.
        /// </summary>
        /// <value>The complement.</value>
        public FilteredCatalog Complement
        {
            get
            {
                this.ThrowIfDisposed();

                if (this._complement == null)
                {
                    FilteredCatalog complement = new FilteredCatalog(this._innerCatalog, p => !this._filter(p), this);
                    lock (this._lock)
                    {
                        if (this._complement == null)
                        {
                            Thread.MemoryBarrier();
                            this._complement = complement;
                            complement = null;
                        }
                    }

                    if (complement != null)
                    {
                        complement.Dispose();
                    }
                }

                return this._complement;
            }
        }

        /// <summary>
        /// Returns the export definitions that match the constraint defined by the specified definition.
        /// </summary>
        /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the
        /// <see cref="ExportDefinition"/> objects to return.</param>
        /// <returns>
        /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the
        /// <see cref="ExportDefinition"/> objects and their associated
        /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined
        /// by <paramref name="definition"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// 	<paramref name="definition"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ObjectDisposedException">
        /// The <see cref="ComposablePartCatalog"/> has been disposed of.
        /// </exception>
        /// <remarks>
        /// 	<note type="inheritinfo">
        /// Overriders of this property should never return <see langword="null"/>, if no
        /// <see cref="ExportDefinition"/> match the conditions defined by
        /// <paramref name="definition"/>, return an empty <see cref="IEnumerable{T}"/>.
        /// </note>
        /// </remarks>
        public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
        {
            this.ThrowIfDisposed();
            Requires.NotNull(definition, "definition");

            var exports = new List<Tuple<ComposablePartDefinition, ExportDefinition>>();
            foreach(var export in this._innerCatalog.GetExports(definition))
            {
                if (this._filter(export.Item1))
                {
                    exports.Add(export);
                }
            }

            return exports;
        }

        /// <summary>
        /// Notify when the contents of the Catalog has changed.
        /// </summary>
        public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed;


        /// <summary>
        /// Notify when the contents of the Catalog is changing.
        /// </summary>
        public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing;


        /// <summary>
        /// Raises the <see cref="E:Changed"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs"/> instance containing the event data.</param>
        protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e)
        {
            EventHandler<ComposablePartCatalogChangeEventArgs> changedEvent = this.Changed;
            if (changedEvent != null)
            {
                changedEvent.Invoke(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="E:Changing"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs"/> instance containing the event data.</param>
        protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e)
        {
            EventHandler<ComposablePartCatalogChangeEventArgs> changingEvent = this.Changing;
            if (changingEvent != null)
            {
                changingEvent.Invoke(this, e);
            }
        }

        private void OnChangedInternal(object sender, ComposablePartCatalogChangeEventArgs e)
        {
            var processedArgs = ProcessEventArgs(e);
            if (processedArgs != null)
            {
                this.OnChanged(this.ProcessEventArgs(processedArgs));
            }
        }

        private void OnChangingInternal(object sender, ComposablePartCatalogChangeEventArgs e)
        {
            var processedArgs = ProcessEventArgs(e);
            if (processedArgs != null)
            {
                this.OnChanging(this.ProcessEventArgs(processedArgs));
            }
        }

        private ComposablePartCatalogChangeEventArgs ProcessEventArgs(ComposablePartCatalogChangeEventArgs e)
        {
            // the constructor for ComposablePartCatalogChangeEventArgs takes a snapshot of the arguments, so we don't have to
            var result = new ComposablePartCatalogChangeEventArgs(
                e.AddedDefinitions.Where(this._filter),
                e.RemovedDefinitions.Where(this._filter),
                e.AtomicComposition);

            // Only fire if we need to
            if (result.AddedDefinitions.FastAny() || result.RemovedDefinitions.FastAny())
            {
                return result;
            }
            else
            {
                return null;
            }
        }

        [DebuggerStepThrough]
        [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")]
        private void ThrowIfDisposed()
        {
            if (this._isDisposed)
            {
                throw ExceptionBuilder.CreateObjectDisposed(this);
            }
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) http://www.ansibleww.com.au
Australia Australia
The Australia born French man who went back to Australia later in life...
Finally got over life long (and mostly hopeless usually, yay!) chronic sicknesses.
Worked in Sydney, Brisbane, Darwin, Billinudgel, Darwin and Melbourne.

Comments and Discussions