1 //---------------------------------------------------------------------
2 // <copyright file="ObjectItemLoadingSessionData.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9 using System.Reflection;
11 using System.Collections.Generic;
12 using System.Diagnostics;
14 namespace System.Data.Metadata.Edm
16 internal sealed class ObjectItemLoadingSessionData
18 private Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader> _loaderFactory;
20 // all the types that we encountered while loading - this may contain types from various assemblies
21 private readonly Dictionary<string, EdmType> _typesInLoading;
25 private bool _conventionBasedRelationshipsAreLoaded = false;
27 private LoadMessageLogger _loadMessageLogger;
29 // list of errors encountered during loading
30 private readonly List<EdmItemError> _errors;
32 // keep the list of new assemblies that got loaded in this load assembly call. The reason why we need to keep a seperate
33 // 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
34 // to the global cache. Hence global cache is never polluted with invalid assemblies
35 private readonly Dictionary<Assembly, MutableAssemblyCacheEntry> _listOfAssembliesLoaded = new Dictionary<Assembly, MutableAssemblyCacheEntry>();
37 // List of known assemblies - this list is initially passed by the caller and we keep adding to it, as and when we load
39 private readonly KnownAssembliesSet _knownAssemblies;
40 private readonly LockedAssemblyCache _lockedAssemblyCache;
41 private readonly HashSet<ObjectItemAssemblyLoader> _loadersThatNeedLevel1PostSessionProcessing;
42 private readonly HashSet<ObjectItemAssemblyLoader> _loadersThatNeedLevel2PostSessionProcessing;
44 private readonly EdmItemCollection _edmItemCollection;
45 private Dictionary<string, KeyValuePair<EdmType, int>> _conventionCSpaceTypeNames;
46 private Dictionary<EdmType, EdmType> _cspaceToOspace;
47 private object _originalLoaderCookie;
48 internal Dictionary<string, EdmType> TypesInLoading { get { return _typesInLoading; } }
49 internal Dictionary<Assembly, MutableAssemblyCacheEntry> AssembliesLoaded { get { return _listOfAssembliesLoaded; } }
50 internal List<EdmItemError> EdmItemErrors { get { return _errors; } }
51 internal KnownAssembliesSet KnownAssemblies { get { return _knownAssemblies; } }
52 internal LockedAssemblyCache LockedAssemblyCache { get { return _lockedAssemblyCache; } }
53 internal EdmItemCollection EdmItemCollection { get { return _edmItemCollection; } }
54 internal Dictionary<EdmType, EdmType> CspaceToOspace { get { return _cspaceToOspace; } }
55 internal bool ConventionBasedRelationshipsAreLoaded
57 get { return _conventionBasedRelationshipsAreLoaded; }
58 set { _conventionBasedRelationshipsAreLoaded = value; }
61 internal LoadMessageLogger LoadMessageLogger
65 return this._loadMessageLogger;
69 // dictionary of types by name (not including namespace), we also track duplicate names
70 // so if one of those types is used we can log an error
71 internal Dictionary<string, KeyValuePair<EdmType, int>> ConventionCSpaceTypeNames
75 if (_edmItemCollection != null && _conventionCSpaceTypeNames == null)
77 _conventionCSpaceTypeNames = new Dictionary<string, KeyValuePair<EdmType, int>>();
79 // create the map and cache it
80 foreach (var edmType in _edmItemCollection.GetItems<EdmType>())
82 if ((edmType is StructuralType && edmType.BuiltInTypeKind != BuiltInTypeKind.AssociationType) || Helper.IsEnumType(edmType))
85 KeyValuePair<EdmType, int> pair;
86 if (_conventionCSpaceTypeNames.TryGetValue(edmType.Name, out pair))
88 _conventionCSpaceTypeNames[edmType.Name] = new KeyValuePair<EdmType, int>(pair.Key, pair.Value + 1);
92 pair = new KeyValuePair<EdmType, int>(edmType, 1);
93 _conventionCSpaceTypeNames.Add(edmType.Name, pair);
98 return _conventionCSpaceTypeNames;
102 internal Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader> ObjectItemAssemblyLoaderFactory
104 get { return _loaderFactory; }
107 if (_loaderFactory != value)
109 Debug.Assert(_loaderFactory == null || _typesInLoading.Count == 0, "Only reset the factory after types have not been loaded or load from the cache");
110 _loaderFactory = value;
115 internal object LoaderCookie
119 // be sure we get the same factory/cookie as we had before... if we had one
120 if (_originalLoaderCookie != null)
122 Debug.Assert(_loaderFactory == null ||
123 (object)_loaderFactory == _originalLoaderCookie, "The loader factory should determine the next loader, so we should always have the same loader factory");
124 return _originalLoaderCookie;
127 return _loaderFactory;
130 internal ObjectItemLoadingSessionData(KnownAssembliesSet knownAssemblies, LockedAssemblyCache lockedAssemblyCache, EdmItemCollection edmItemCollection, Action<String> logLoadMessage, object loaderCookie)
132 Debug.Assert(loaderCookie == null || loaderCookie is Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>, "This is a bad loader cookie");
134 _typesInLoading = new Dictionary<string, EdmType>(StringComparer.Ordinal);
135 _errors = new List<EdmItemError>();
136 _knownAssemblies = knownAssemblies;
137 _lockedAssemblyCache = lockedAssemblyCache;
138 _loadersThatNeedLevel1PostSessionProcessing = new HashSet<ObjectItemAssemblyLoader>();
139 _loadersThatNeedLevel2PostSessionProcessing = new HashSet<ObjectItemAssemblyLoader>();
140 _edmItemCollection = edmItemCollection;
141 _loadMessageLogger = new LoadMessageLogger(logLoadMessage);
142 _cspaceToOspace = new Dictionary<EdmType, EdmType>();
143 _loaderFactory = (Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>)loaderCookie;
144 _originalLoaderCookie = loaderCookie;
145 if (_loaderFactory == ObjectItemConventionAssemblyLoader.Create && _edmItemCollection != null)
147 foreach (KnownAssemblyEntry entry in _knownAssemblies.GetEntries(_loaderFactory, edmItemCollection))
149 foreach (EdmType type in entry.CacheEntry.TypesInAssembly.OfType<EdmType>())
151 if (Helper.IsEntityType(type))
153 ClrEntityType entityType = (ClrEntityType)type;
154 _cspaceToOspace.Add(_edmItemCollection.GetItem<StructuralType>(entityType.CSpaceTypeName), entityType);
156 else if (Helper.IsComplexType(type))
158 ClrComplexType complexType = (ClrComplexType)type;
159 _cspaceToOspace.Add(_edmItemCollection.GetItem<StructuralType>(complexType.CSpaceTypeName), complexType);
161 else if(Helper.IsEnumType(type))
163 ClrEnumType enumType = (ClrEnumType)type;
164 _cspaceToOspace.Add(_edmItemCollection.GetItem<EnumType>(enumType.CSpaceTypeName), enumType);
168 Debug.Assert(Helper.IsAssociationType(type));
169 _cspaceToOspace.Add(_edmItemCollection.GetItem<StructuralType>(type.FullName), type);
177 internal void RegisterForLevel1PostSessionProcessing(ObjectItemAssemblyLoader loader)
179 _loadersThatNeedLevel1PostSessionProcessing.Add(loader);
182 internal void RegisterForLevel2PostSessionProcessing(ObjectItemAssemblyLoader loader)
184 _loadersThatNeedLevel2PostSessionProcessing.Add(loader);
187 internal void CompleteSession()
189 foreach (ObjectItemAssemblyLoader loader in _loadersThatNeedLevel1PostSessionProcessing)
191 loader.OnLevel1SessionProcessing();
194 foreach (ObjectItemAssemblyLoader loader in _loadersThatNeedLevel2PostSessionProcessing)
196 loader.OnLevel2SessionProcessing();