File: System\Addin\Hosting\Store\PipelineComponent.cs
Project: ndp\fx\src\AddIn\AddIn\System.AddIn.csproj (System.AddIn)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*============================================================
**
** Class:  PipelineComponent
**
** Purpose: Base class representing parts of the add-in 
**     pipeline, from the host to the contract to the addin.
**
===========================================================*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Diagnostics;
using System.AddIn.MiniReflection;
using System.AddIn.Pipeline;
 
using System.Diagnostics.Contracts;
using TypeInfo=System.AddIn.MiniReflection.TypeInfo;
 
namespace System.AddIn
{
    [Serializable]
    internal enum PipelineComponentType
    {
        HostAdapter,
        Contract,
        AddInAdapter,
        AddInBase,
        AddIn
    }
 
    [Serializable]
    internal abstract class PipelineComponent
    {
        private TypeInfo _typeInfo;
        private String _location;         // fully qualified path, known after deserialization
        private String _relativeLocation; // relative to the add-in root or pipeline root.
        private bool _connectedToNeighbors;
        private bool _haveSetRootDirectory; // Whether the add-in root or pipeline root has been set.
 
        // Since these dictionaries are read-only after initialization and they are often empty,
        // a perf optimization is to have the empty ones be shared.
        private IDictionary<String, String> _qualificationData;
 
        internal static readonly IDictionary<String, String> s_emptyDictionary = 
            new ReadOnlyDictionary<String, String>(new Dictionary<String, String>());
 
        private static volatile Type s_IContractInReflectionLoaderContext;
        private static volatile Type s_ContractAttrInReflectionLoaderContext;
        private static volatile Type s_AddInAdapterAttrInReflectionLoaderContext;
        private static volatile Type s_AddInBaseAttrInReflectionLoaderContext;
        private static volatile Type s_AddInAttrInReflectionLoaderContext;
        private static volatile Type s_QualificationDataAttrInReflectionLoaderContext;
 
 
        internal PipelineComponent(TypeInfo typeInfo, String assemblyLocation)
        {
            if (typeInfo == null)
                throw new ArgumentNullException("typeInfo");
            if (assemblyLocation == null)
                throw new ArgumentNullException("assemblyLocation");
            System.Diagnostics.Contracts.Contract.EndContractBlock();
            
            _typeInfo = typeInfo;
            if (Path.IsPathRooted(assemblyLocation)) {
                // For FindAddIn case, we know the full location;
                _location = assemblyLocation;
                _haveSetRootDirectory = true;
            }
            else {
                _relativeLocation = assemblyLocation;
            }
 
            // load the qualification data, either from reflection or minireflection, as appropriate
            if (_typeInfo.HasReflectionType)
            {
                IList<CustomAttributeData> cas =CustomAttributeData.GetCustomAttributes(_typeInfo.ReflectionType); 
                Dictionary<String, String> dictionary = new Dictionary<String, String>();
                foreach (CustomAttributeData ca in cas)
                {
                    if (Object.ReferenceEquals(ca.Constructor.DeclaringType, s_QualificationDataAttrInReflectionLoaderContext))
                    {
                        IList<CustomAttributeTypedArgument> args = ca.ConstructorArguments;
                        String key = (String)args[0].Value;
                        String val = (String)args[1].Value;
                        dictionary[key] = val;
                    }
                }
                _qualificationData = dictionary.Count == 0 ? s_emptyDictionary : 
                    new ReadOnlyDictionary<String, String>(dictionary);
            }
            else
            {
                Type qualificationDataAttribute = typeof (QualificationDataAttribute);
                MiniCustomAttributeInfo[] cas = typeInfo.GetCustomAttributeInfos(qualificationDataAttribute);
                Dictionary<String, String> dictionary = new Dictionary<String, String>();
                if (cas != null && cas.Length > 0)
                {
                    foreach (MiniCustomAttributeInfo ca in cas)
                    {
                        MiniCustomAttributeFixedArgInfo[] fai = ca.FixedArgs;
                        String key = (String)fai[0].Value;
                        String val = (String)fai[1].Value;
                        dictionary[key] = val;
                    }
                }
                _qualificationData = dictionary.Count == 0 ? s_emptyDictionary : 
                    new ReadOnlyDictionary<String, String>(dictionary);
            }
        }
 
        internal IDictionary<String, String> QualificationData
        {
            get { return _qualificationData; }
        }
 
        protected static Type IContractInReflectionLoaderContext {
            get {
                System.Diagnostics.Contracts.Contract.Assert(s_IContractInReflectionLoaderContext != null);
                return s_IContractInReflectionLoaderContext;
            }
        }
 
        internal static Type ContractAttributeInReflectionLoaderContext {
            get {
                System.Diagnostics.Contracts.Contract.Assert(s_ContractAttrInReflectionLoaderContext != null);
                return s_ContractAttrInReflectionLoaderContext;
            }
        }
 
        internal static Type AddInAdapterAttributeInReflectionLoaderContext {
            get {
                System.Diagnostics.Contracts.Contract.Assert(s_AddInAdapterAttrInReflectionLoaderContext != null);
                return s_AddInAdapterAttrInReflectionLoaderContext;
            }
        }
 
        internal static Type AddInBaseAttributeInReflectionLoaderContext {
            get {
                System.Diagnostics.Contracts.Contract.Assert(s_AddInBaseAttrInReflectionLoaderContext != null);
                return s_AddInBaseAttrInReflectionLoaderContext;
            }
        }
 
        internal static Type AddInAttributeInReflectionLoaderContext {
            get {
                System.Diagnostics.Contracts.Contract.Assert(s_AddInAttrInReflectionLoaderContext != null);
                return s_AddInAttrInReflectionLoaderContext;
            }
        }
 
        internal static void SetTypesFromReflectionLoaderContext(System.Reflection.Assembly systemAddInInReflLoaderContext,
                                                                 System.Reflection.Assembly systemAddInContractsInReflLoaderContext)
        {
            System.Diagnostics.Contracts.Contract.Requires(systemAddInInReflLoaderContext != null);
            System.Diagnostics.Contracts.Contract.Requires(systemAddInInReflLoaderContext.ReflectionOnly);
            System.Diagnostics.Contracts.Contract.Requires(systemAddInContractsInReflLoaderContext != null);
            System.Diagnostics.Contracts.Contract.Requires(systemAddInContractsInReflLoaderContext.ReflectionOnly);
 
            s_IContractInReflectionLoaderContext = systemAddInContractsInReflLoaderContext.GetType(typeof(System.AddIn.Contract.IContract).FullName, true);
            s_ContractAttrInReflectionLoaderContext =systemAddInContractsInReflLoaderContext.GetType("System.AddIn.Pipeline.AddInContractAttribute", true);
            s_QualificationDataAttrInReflectionLoaderContext = systemAddInContractsInReflLoaderContext.GetType("System.AddIn.Pipeline.QualificationDataAttribute", true);
            s_AddInAdapterAttrInReflectionLoaderContext = systemAddInInReflLoaderContext.GetType("System.AddIn.Pipeline.AddInAdapterAttribute", true);
            s_AddInBaseAttrInReflectionLoaderContext = systemAddInInReflLoaderContext.GetType("System.AddIn.Pipeline.AddInBaseAttribute", true);
            s_AddInAttrInReflectionLoaderContext = systemAddInInReflLoaderContext.GetType("System.AddIn.AddInAttribute", true);
        }
 
        internal void SetRootDirectory(String root)
        {
            System.Diagnostics.Contracts.Contract.Requires(Path.IsPathRooted(root));
            // Note that the same pipeline component may show up in multiple pipelines,
            // and we can't do this operation twice.
            if (!_haveSetRootDirectory) {
                System.Diagnostics.Contracts.Contract.Assert(!Path.IsPathRooted(_relativeLocation));
 
                _location = Path.Combine(root, _relativeLocation);
                _haveSetRootDirectory = true;
            }
        }
 
        public String Location {
            get {
                System.Diagnostics.Contracts.Contract.Assert(_haveSetRootDirectory, "You must set this component's root directory before getting an absolute path.  Either call SetRootDirectory or use RelativeLocation instead.");
                return _location;
            }
        }
 
        internal String RelativeLocation {
            get {
                return _relativeLocation;
            }
        }
 
        protected String BestAvailableLocation {
            get {
                System.Diagnostics.Contracts.Contract.Ensures(System.Diagnostics.Contracts.Contract.Result<String>() != null);
                if (_haveSetRootDirectory)
                    return _location;
                return _relativeLocation;
            }
        }
 
        public String Name {
            get {
                System.Diagnostics.Contracts.Contract.Ensures(System.Diagnostics.Contracts.Contract.Result<String>() != null);
                return _typeInfo.Name;
            }
        }
 
        public TypeInfo TypeInfo {
            get { return _typeInfo; }
        }
 
        public String FullName {
            get {
                return _typeInfo.FullName;
            }
        }
 
        public bool ConnectedToNeighbors {
            get { return _connectedToNeighbors; }
            set { _connectedToNeighbors = value; }
        }
 
        // @
 
 
 
 
 
 
        internal virtual bool Validate(Type type, Collection<String> warnings)
        {
            return Validate(new TypeInfo(type), warnings);
        }
 
        // Finish the initialization, and ensure this type is a valid component
        // for use in the add-in model.  On failure, log a message & return false.
        // Derived classes should do their own validation and then call this one.
        internal virtual bool Validate(TypeInfo type, Collection<String> warnings)
        {
            if (type.IsGeneric)
            {
                warnings.Add(String.Format(System.Globalization.CultureInfo.CurrentCulture, Res.ComponentUnusableBecauseItIsGeneric, type.Name));
                return false;
            }
            return true;
        }
 
        // used in AddIn class and HostAdapter class
        // Since MiniReflection doesn't support generics, we do a "best effort" while generating this list.
        [System.Security.SecuritySafeCritical]
        internal static TypeInfo[] FindBaseTypesAndInterfaces(TypeInfo type)
        {
            TypeInfo currentTypeInfo = type;
            TypeInfo objectType = new TypeInfo(typeof(Object));
            List<TypeInfo> infos = new List<TypeInfo>();
 
            try
            {
                //we walk up the hierarchy as far as we can until we can't
                //get the types anymore...
                while (!currentTypeInfo.Equals(objectType))
                {
                    // To get the base type and interfaces, we will need to resolve a TypeRef to a TypeDef first
                    currentTypeInfo = currentTypeInfo.TryGetTypeDef();
                    if (currentTypeInfo != null)
                    {
                        TypeInfo[] interfaces = currentTypeInfo.GetInterfaces();
                        if (interfaces != null)
                            infos.AddRange(interfaces);
 
                        TypeInfo baseType = currentTypeInfo.BaseType;
                        infos.Add(baseType);
                        currentTypeInfo = baseType;
                    }
                    else
                    {
                        // we have reached the limit of what we can resolve in the addin/hostadapter's folder
                        break;
                    }
                }
            }
            catch (GenericsNotImplementedException) 
            {
                // Since GetInterfaces() ignores all generic interfaces, we'll only come here if we encounter a generic base class.
                // We'll ignore the generic base class and return whatever bases we found earlier.
            }
 
            return infos.ToArray();
        }
 
    }
}