bfb63d99f7ba33295fd781040dee9b5aab6dda1b
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Metadata / ObjectLayer / ObjectItemLoadingSessionData.cs
1 //---------------------------------------------------------------------
2 // <copyright file="ObjectItemLoadingSessionData.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       [....]
7 // @backupOwner [....]
8 //---------------------------------------------------------------------
9 using System.Reflection;
10 using System.Linq;
11 using System.Collections.Generic;
12 using System.Diagnostics;
13
14 namespace System.Data.Metadata.Edm
15 {
16     internal sealed class ObjectItemLoadingSessionData
17     {
18         private Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader> _loaderFactory;
19
20         // all the types that we encountered while loading - this may contain types from various assemblies
21         private readonly Dictionary<string, EdmType> _typesInLoading;
22         
23         // 
24
25         private bool _conventionBasedRelationshipsAreLoaded = false;
26
27         private LoadMessageLogger _loadMessageLogger;
28
29         // list of errors encountered during loading
30         private readonly List<EdmItemError> _errors;
31
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>();
36
37         // List of known assemblies - this list is initially passed by the caller and we keep adding to it, as and when we load
38         // an assembly
39         private readonly KnownAssembliesSet _knownAssemblies;
40         private readonly LockedAssemblyCache _lockedAssemblyCache;
41         private readonly HashSet<ObjectItemAssemblyLoader> _loadersThatNeedLevel1PostSessionProcessing;
42         private readonly HashSet<ObjectItemAssemblyLoader> _loadersThatNeedLevel2PostSessionProcessing;
43
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 
56         { 
57             get { return _conventionBasedRelationshipsAreLoaded;  }
58             set { _conventionBasedRelationshipsAreLoaded = value; }
59         }
60
61         internal LoadMessageLogger LoadMessageLogger
62         { 
63             get 
64             { 
65                 return this._loadMessageLogger; 
66             }
67         }
68
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 
72         { 
73             get 
74             {
75                 if (_edmItemCollection != null && _conventionCSpaceTypeNames == null)
76                 {
77                     _conventionCSpaceTypeNames = new Dictionary<string, KeyValuePair<EdmType, int>>();
78
79                     // create the map and cache it
80                     foreach (var edmType in _edmItemCollection.GetItems<EdmType>())
81                     {
82                         if ((edmType is StructuralType && edmType.BuiltInTypeKind != BuiltInTypeKind.AssociationType) || Helper.IsEnumType(edmType))
83                         {
84
85                             KeyValuePair<EdmType, int> pair;
86                             if (_conventionCSpaceTypeNames.TryGetValue(edmType.Name, out pair))
87                             {
88                                 _conventionCSpaceTypeNames[edmType.Name] = new KeyValuePair<EdmType, int>(pair.Key, pair.Value + 1);
89                             }
90                             else
91                             {
92                                 pair = new KeyValuePair<EdmType, int>(edmType, 1);
93                                 _conventionCSpaceTypeNames.Add(edmType.Name, pair);
94                             }
95                         }
96                     }
97                 }
98                 return _conventionCSpaceTypeNames;
99             } 
100         }
101
102         internal Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader> ObjectItemAssemblyLoaderFactory
103         {
104             get { return _loaderFactory; }
105             set
106             {
107                 if (_loaderFactory != value)
108                 {
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;
111                 }
112             }
113         }
114
115         internal object LoaderCookie
116         {
117             get
118             {
119                 // be sure we get the same factory/cookie as we had before... if we had one
120                 if (_originalLoaderCookie != null)
121                 {
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;
125                 }
126
127                 return _loaderFactory;
128             }
129         }
130         internal ObjectItemLoadingSessionData(KnownAssembliesSet knownAssemblies, LockedAssemblyCache lockedAssemblyCache, EdmItemCollection edmItemCollection, Action<String> logLoadMessage, object loaderCookie)
131         {
132             Debug.Assert(loaderCookie == null || loaderCookie is Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>, "This is a bad loader cookie");
133             
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)
146             {
147                 foreach (KnownAssemblyEntry entry in _knownAssemblies.GetEntries(_loaderFactory, edmItemCollection))
148                 {
149                     foreach (EdmType type in entry.CacheEntry.TypesInAssembly.OfType<EdmType>())
150                     {
151                         if (Helper.IsEntityType(type))
152                         {
153                             ClrEntityType entityType = (ClrEntityType)type;
154                             _cspaceToOspace.Add(_edmItemCollection.GetItem<StructuralType>(entityType.CSpaceTypeName), entityType);
155                         }
156                         else if (Helper.IsComplexType(type))
157                         {
158                             ClrComplexType complexType = (ClrComplexType)type;
159                             _cspaceToOspace.Add(_edmItemCollection.GetItem<StructuralType>(complexType.CSpaceTypeName), complexType);
160                         }
161                         else if(Helper.IsEnumType(type))
162                         {
163                             ClrEnumType enumType = (ClrEnumType)type;
164                             _cspaceToOspace.Add(_edmItemCollection.GetItem<EnumType>(enumType.CSpaceTypeName), enumType);
165                         }
166                         else
167                         {
168                             Debug.Assert(Helper.IsAssociationType(type));
169                             _cspaceToOspace.Add(_edmItemCollection.GetItem<StructuralType>(type.FullName), type);
170                         }
171                     }
172                 }
173             }
174
175         }
176
177         internal void RegisterForLevel1PostSessionProcessing(ObjectItemAssemblyLoader loader)
178         {
179             _loadersThatNeedLevel1PostSessionProcessing.Add(loader);
180         }
181
182         internal void RegisterForLevel2PostSessionProcessing(ObjectItemAssemblyLoader loader)
183         {
184             _loadersThatNeedLevel2PostSessionProcessing.Add(loader);
185         }
186         
187         internal void CompleteSession()
188         {
189             foreach (ObjectItemAssemblyLoader loader in _loadersThatNeedLevel1PostSessionProcessing)
190             {
191                 loader.OnLevel1SessionProcessing();
192             }
193
194             foreach (ObjectItemAssemblyLoader loader in _loadersThatNeedLevel2PostSessionProcessing)
195             {
196                 loader.OnLevel2SessionProcessing();
197             }
198         }
199     }
200 }