1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
//---------------------------------------------------------------------
// <copyright file="ObjectItemLoadingSessionData.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
namespace System.Data.Metadata.Edm
{
internal sealed class ObjectItemLoadingSessionData
{
private Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader> _loaderFactory;
// all the types that we encountered while loading - this may contain types from various assemblies
private readonly Dictionary<string, EdmType> _typesInLoading;
//
private bool _conventionBasedRelationshipsAreLoaded = false;
private LoadMessageLogger _loadMessageLogger;
// list of errors encountered during loading
private readonly List<EdmItemError> _errors;
// keep the list of new assemblies that got loaded in this load assembly call. The reason why we need to keep a seperate
// list of assemblies is that we keep track of errors, and if there are no errors, only then do we add the list of assemblies
// to the global cache. Hence global cache is never polluted with invalid assemblies
private readonly Dictionary<Assembly, MutableAssemblyCacheEntry> _listOfAssembliesLoaded = new Dictionary<Assembly, MutableAssemblyCacheEntry>();
// List of known assemblies - this list is initially passed by the caller and we keep adding to it, as and when we load
// an assembly
private readonly KnownAssembliesSet _knownAssemblies;
private readonly LockedAssemblyCache _lockedAssemblyCache;
private readonly HashSet<ObjectItemAssemblyLoader> _loadersThatNeedLevel1PostSessionProcessing;
private readonly HashSet<ObjectItemAssemblyLoader> _loadersThatNeedLevel2PostSessionProcessing;
private readonly EdmItemCollection _edmItemCollection;
private Dictionary<string, KeyValuePair<EdmType, int>> _conventionCSpaceTypeNames;
private Dictionary<EdmType, EdmType> _cspaceToOspace;
private object _originalLoaderCookie;
internal Dictionary<string, EdmType> TypesInLoading { get { return _typesInLoading; } }
internal Dictionary<Assembly, MutableAssemblyCacheEntry> AssembliesLoaded { get { return _listOfAssembliesLoaded; } }
internal List<EdmItemError> EdmItemErrors { get { return _errors; } }
internal KnownAssembliesSet KnownAssemblies { get { return _knownAssemblies; } }
internal LockedAssemblyCache LockedAssemblyCache { get { return _lockedAssemblyCache; } }
internal EdmItemCollection EdmItemCollection { get { return _edmItemCollection; } }
internal Dictionary<EdmType, EdmType> CspaceToOspace { get { return _cspaceToOspace; } }
internal bool ConventionBasedRelationshipsAreLoaded
{
get { return _conventionBasedRelationshipsAreLoaded; }
set { _conventionBasedRelationshipsAreLoaded = value; }
}
internal LoadMessageLogger LoadMessageLogger
{
get
{
return this._loadMessageLogger;
}
}
// dictionary of types by name (not including namespace), we also track duplicate names
// so if one of those types is used we can log an error
internal Dictionary<string, KeyValuePair<EdmType, int>> ConventionCSpaceTypeNames
{
get
{
if (_edmItemCollection != null && _conventionCSpaceTypeNames == null)
{
_conventionCSpaceTypeNames = new Dictionary<string, KeyValuePair<EdmType, int>>();
// create the map and cache it
foreach (var edmType in _edmItemCollection.GetItems<EdmType>())
{
if ((edmType is StructuralType && edmType.BuiltInTypeKind != BuiltInTypeKind.AssociationType) || Helper.IsEnumType(edmType))
{
KeyValuePair<EdmType, int> pair;
if (_conventionCSpaceTypeNames.TryGetValue(edmType.Name, out pair))
{
_conventionCSpaceTypeNames[edmType.Name] = new KeyValuePair<EdmType, int>(pair.Key, pair.Value + 1);
}
else
{
pair = new KeyValuePair<EdmType, int>(edmType, 1);
_conventionCSpaceTypeNames.Add(edmType.Name, pair);
}
}
}
}
return _conventionCSpaceTypeNames;
}
}
internal Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader> ObjectItemAssemblyLoaderFactory
{
get { return _loaderFactory; }
set
{
if (_loaderFactory != value)
{
Debug.Assert(_loaderFactory == null || _typesInLoading.Count == 0, "Only reset the factory after types have not been loaded or load from the cache");
_loaderFactory = value;
}
}
}
internal object LoaderCookie
{
get
{
// be sure we get the same factory/cookie as we had before... if we had one
if (_originalLoaderCookie != null)
{
Debug.Assert(_loaderFactory == null ||
(object)_loaderFactory == _originalLoaderCookie, "The loader factory should determine the next loader, so we should always have the same loader factory");
return _originalLoaderCookie;
}
return _loaderFactory;
}
}
internal ObjectItemLoadingSessionData(KnownAssembliesSet knownAssemblies, LockedAssemblyCache lockedAssemblyCache, EdmItemCollection edmItemCollection, Action<String> logLoadMessage, object loaderCookie)
{
Debug.Assert(loaderCookie == null || loaderCookie is Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>, "This is a bad loader cookie");
_typesInLoading = new Dictionary<string, EdmType>(StringComparer.Ordinal);
_errors = new List<EdmItemError>();
_knownAssemblies = knownAssemblies;
_lockedAssemblyCache = lockedAssemblyCache;
_loadersThatNeedLevel1PostSessionProcessing = new HashSet<ObjectItemAssemblyLoader>();
_loadersThatNeedLevel2PostSessionProcessing = new HashSet<ObjectItemAssemblyLoader>();
_edmItemCollection = edmItemCollection;
_loadMessageLogger = new LoadMessageLogger(logLoadMessage);
_cspaceToOspace = new Dictionary<EdmType, EdmType>();
_loaderFactory = (Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>)loaderCookie;
_originalLoaderCookie = loaderCookie;
if (_loaderFactory == ObjectItemConventionAssemblyLoader.Create && _edmItemCollection != null)
{
foreach (KnownAssemblyEntry entry in _knownAssemblies.GetEntries(_loaderFactory, edmItemCollection))
{
foreach (EdmType type in entry.CacheEntry.TypesInAssembly.OfType<EdmType>())
{
if (Helper.IsEntityType(type))
{
ClrEntityType entityType = (ClrEntityType)type;
_cspaceToOspace.Add(_edmItemCollection.GetItem<StructuralType>(entityType.CSpaceTypeName), entityType);
}
else if (Helper.IsComplexType(type))
{
ClrComplexType complexType = (ClrComplexType)type;
_cspaceToOspace.Add(_edmItemCollection.GetItem<StructuralType>(complexType.CSpaceTypeName), complexType);
}
else if(Helper.IsEnumType(type))
{
ClrEnumType enumType = (ClrEnumType)type;
_cspaceToOspace.Add(_edmItemCollection.GetItem<EnumType>(enumType.CSpaceTypeName), enumType);
}
else
{
Debug.Assert(Helper.IsAssociationType(type));
_cspaceToOspace.Add(_edmItemCollection.GetItem<StructuralType>(type.FullName), type);
}
}
}
}
}
internal void RegisterForLevel1PostSessionProcessing(ObjectItemAssemblyLoader loader)
{
_loadersThatNeedLevel1PostSessionProcessing.Add(loader);
}
internal void RegisterForLevel2PostSessionProcessing(ObjectItemAssemblyLoader loader)
{
_loadersThatNeedLevel2PostSessionProcessing.Add(loader);
}
internal void CompleteSession()
{
foreach (ObjectItemAssemblyLoader loader in _loadersThatNeedLevel1PostSessionProcessing)
{
loader.OnLevel1SessionProcessing();
}
foreach (ObjectItemAssemblyLoader loader in _loadersThatNeedLevel2PostSessionProcessing)
{
loader.OnLevel2SessionProcessing();
}
}
}
}
|