Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@ -0,0 +1,164 @@
//---------------------------------------------------------------------
// <copyright file="AssemblyCache.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Data.Common.Utils;
using System.Diagnostics;
using System.Reflection;
namespace System.Data.Metadata.Edm
{
internal static class AssemblyCache
{
// Global Assembly Cache
private readonly static Dictionary<Assembly, ImmutableAssemblyCacheEntry> s_globalAssemblyCache = new Dictionary<Assembly, ImmutableAssemblyCacheEntry>();
private static object _assemblyCacheLock = new object();
//List of assemblies having view gen attribute. We cache these things if we discover
//these assemblies while looking for O-space metadata.
private static IList<Assembly> s_viewGenAssemblies = new ThreadSafeList<Assembly>();
internal static LockedAssemblyCache AquireLockedAssemblyCache()
{
return new LockedAssemblyCache(_assemblyCacheLock, s_globalAssemblyCache);
}
internal static void LoadAssembly(Assembly assembly, bool loadReferencedAssemblies,
KnownAssembliesSet knownAssemblies, out Dictionary<string, EdmType> typesInLoading, out List<EdmItemError> errors)
{
object loaderCookie = null;
LoadAssembly(assembly, loadReferencedAssemblies, knownAssemblies, null, null, ref loaderCookie, out typesInLoading, out errors);
}
internal static void LoadAssembly(Assembly assembly, bool loadReferencedAssemblies,
KnownAssembliesSet knownAssemblies, EdmItemCollection edmItemCollection, Action<String> logLoadMessage, ref object loaderCookie, out Dictionary<string, EdmType> typesInLoading, out List<EdmItemError> errors)
{
Debug.Assert(loaderCookie == null || loaderCookie is Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>, "This is a bad loader cookie");
typesInLoading = null;
errors = null;
using (LockedAssemblyCache lockedAssemblyCache = AssemblyCache.AquireLockedAssemblyCache())
{
ObjectItemLoadingSessionData loadingData = new ObjectItemLoadingSessionData(knownAssemblies, lockedAssemblyCache, edmItemCollection, logLoadMessage, loaderCookie);
LoadAssembly(assembly, loadReferencedAssemblies, loadingData);
loaderCookie = loadingData.LoaderCookie;
// resolve references to top level types (base types, navigation properties returns and associations, and complex type properties)
loadingData.CompleteSession();
if (loadingData.EdmItemErrors.Count == 0)
{
// do the validation for the all the new types
// Now, perform validation on all the new types
EdmValidator validator = new EdmValidator();
validator.SkipReadOnlyItems = true;
validator.Validate(loadingData.TypesInLoading.Values, loadingData.EdmItemErrors);
// Update the global cache if there are no errors
if (loadingData.EdmItemErrors.Count == 0)
{
if (ObjectItemAssemblyLoader.IsAttributeLoader(loadingData.ObjectItemAssemblyLoaderFactory))
{
// we only cache items from the attribute loader globally, the
// items loaded by convention will change depending on the cspace
// provided. cspace will have a cache of it's own for assemblies
UpdateCache(lockedAssemblyCache, loadingData.AssembliesLoaded);
}
else if (loadingData.EdmItemCollection != null &&
ObjectItemAssemblyLoader.IsConventionLoader(loadingData.ObjectItemAssemblyLoaderFactory))
{
UpdateCache(loadingData.EdmItemCollection, loadingData.AssembliesLoaded);
}
}
}
if (loadingData.TypesInLoading.Count > 0)
{
foreach (EdmType edmType in loadingData.TypesInLoading.Values)
{
edmType.SetReadOnly();
}
}
// Update the out parameters once you are done with loading
typesInLoading = loadingData.TypesInLoading;
errors = loadingData.EdmItemErrors;
}
}
private static void LoadAssembly(Assembly assembly, bool loadReferencedAssemblies, ObjectItemLoadingSessionData loadingData)
{
// Check if the assembly is already loaded
KnownAssemblyEntry entry;
bool shouldLoadReferences = false;
if (loadingData.KnownAssemblies.TryGetKnownAssembly(assembly, loadingData.ObjectItemAssemblyLoaderFactory, loadingData.EdmItemCollection, out entry))
{
shouldLoadReferences = !entry.ReferencedAssembliesAreLoaded && loadReferencedAssemblies;
}
else
{
ObjectItemAssemblyLoader loader = ObjectItemAssemblyLoader.CreateLoader(assembly, loadingData);
loader.Load();
shouldLoadReferences = loadReferencedAssemblies;
}
if (shouldLoadReferences)
{
if (entry == null && loadingData.KnownAssemblies.TryGetKnownAssembly(assembly, loadingData.ObjectItemAssemblyLoaderFactory, loadingData.EdmItemCollection, out entry) ||
entry != null)
{
entry.ReferencedAssembliesAreLoaded = true;
}
Debug.Assert(entry != null, "we should always have an entry, why don't we?");
// We will traverse through all the statically linked assemblies and their dependencies.
// Only assemblies with the EdmSchemaAttribute will be loaded and rest will be ignored
// Even if the schema attribute is missing, we should still check all the dependent assemblies
// any of the dependent assemblies can have the schema attribute
// After the given assembly has been loaded, check on the flag in _knownAssemblies to see if it has already
// been recursively loaded. The flag can be true if it was already loaded before this function was called
foreach (Assembly referencedAssembly in MetadataAssemblyHelper.GetNonSystemReferencedAssemblies(assembly))
{
// filter out "known" assemblies to prevent unnecessary loading
// recursive call
LoadAssembly(referencedAssembly, loadReferencedAssemblies, loadingData);
}
}
}
private static void UpdateCache(EdmItemCollection edmItemCollection, Dictionary<Assembly, MutableAssemblyCacheEntry> assemblies)
{
foreach (var entry in assemblies)
{
edmItemCollection.ConventionalOcCache.AddAssemblyToOcCacheFromAssemblyCache(
entry.Key, new ImmutableAssemblyCacheEntry(entry.Value));
}
}
private static void UpdateCache(LockedAssemblyCache lockedAssemblyCache, Dictionary<Assembly, MutableAssemblyCacheEntry> assemblies)
{
foreach (KeyValuePair<Assembly, MutableAssemblyCacheEntry> entry in assemblies)
{
// Add all the assemblies from the loading context to the global cache
lockedAssemblyCache.Add(entry.Key, new ImmutableAssemblyCacheEntry(entry.Value));
}
}
internal static IList<Assembly> ViewGenerationAssemblies
{
get
{
return s_viewGenAssemblies;
}
}
}
}

View File

@ -0,0 +1,40 @@
//---------------------------------------------------------------------
// <copyright file="AssemblyCacheEntry.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Reflection;
namespace System.Data.Metadata.Edm
{
internal abstract class AssemblyCacheEntry
{
internal abstract IList<EdmType> TypesInAssembly { get; }
internal abstract IList<Assembly> ClosureAssemblies { get; }
internal bool TryGetEdmType(string typeName, out EdmType edmType)
{
edmType = null;
foreach (EdmType loadedEdmType in this.TypesInAssembly)
{
if (loadedEdmType.Identity == typeName)
{
edmType = loadedEdmType;
break;
}
}
return (edmType != null);
}
internal bool ContainsType(string typeName)
{
EdmType edmType = null;
return TryGetEdmType(typeName, out edmType);
}
}
}

View File

@ -0,0 +1,37 @@
//---------------------------------------------------------------------
// <copyright file="ImmutableAssemblyCacheEntry.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Reflection;
namespace System.Data.Metadata.Edm
{
internal partial class ImmutableAssemblyCacheEntry : AssemblyCacheEntry
{
// types in "this" assembly
private readonly System.Collections.ObjectModel.ReadOnlyCollection<EdmType> _typesInAssembly;
// other assemblies referenced by types we care about in "this" assembly
private readonly System.Collections.ObjectModel.ReadOnlyCollection<Assembly> _closureAssemblies;
internal ImmutableAssemblyCacheEntry(MutableAssemblyCacheEntry mutableEntry)
{
_typesInAssembly = new List<EdmType>(mutableEntry.TypesInAssembly).AsReadOnly();
_closureAssemblies = new List<Assembly>(mutableEntry.ClosureAssemblies).AsReadOnly();
}
internal override IList<EdmType> TypesInAssembly
{
get { return _typesInAssembly; }
}
internal override IList<Assembly> ClosureAssemblies
{
get { return _closureAssemblies; }
}
}
}

View File

@ -0,0 +1,90 @@
//---------------------------------------------------------------------
// <copyright file="KnownAssembliesSet.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Diagnostics;
namespace System.Data.Metadata.Edm
{
/// <summary>
/// This class is responsible for keeping track of which assemblies we have already
/// considered so we don't reconsider them again.
///
/// The current rules for an assembly to be "seen" is
/// 1. It is already in our dictionary
/// AND
/// 1. We are in attribute loading mode
/// OR
/// 2. We have seen it already with a non null EdmItemCollection
/// OR
/// 3. We are seeing it with a null EdmItemCollection this time
/// </summary>
internal class KnownAssembliesSet
{
private Dictionary<Assembly, KnownAssemblyEntry> _assemblies;
internal KnownAssembliesSet()
{
_assemblies = new Dictionary<Assembly, KnownAssemblyEntry>();
}
internal KnownAssembliesSet(KnownAssembliesSet set)
{
_assemblies = new Dictionary<Assembly, KnownAssemblyEntry>(set._assemblies);
}
internal bool TryGetKnownAssembly(Assembly assembly, object loaderCookie, EdmItemCollection itemCollection, out KnownAssemblyEntry entry)
{
if (!_assemblies.TryGetValue(assembly, out entry))
{
return false;
}
if (!entry.HaveSeenInCompatibleContext(loaderCookie, itemCollection))
{
return false;
}
return true;
}
internal IEnumerable<Assembly> Assemblies
{
get { return _assemblies.Keys; }
}
public IEnumerable<KnownAssemblyEntry> GetEntries(object loaderCookie, EdmItemCollection itemCollection)
{
return _assemblies.Values.Where(e => e.HaveSeenInCompatibleContext(loaderCookie, itemCollection));
}
internal bool Contains(Assembly assembly, object loaderCookie, EdmItemCollection itemCollection)
{
KnownAssemblyEntry entry;
return TryGetKnownAssembly(assembly, loaderCookie, itemCollection, out entry);
}
internal void Add(Assembly assembly, KnownAssemblyEntry knownAssemblyEntry)
{
KnownAssemblyEntry current;
if (_assemblies.TryGetValue(assembly, out current))
{
Debug.Assert(current.SeenWithEdmItemCollection != knownAssemblyEntry.SeenWithEdmItemCollection &&
knownAssemblyEntry.SeenWithEdmItemCollection, "should only be updating if we haven't seen it with an edmItemCollection yet.");
_assemblies[assembly] = knownAssemblyEntry;
}
else
{
_assemblies.Add(assembly, knownAssemblyEntry);
}
}
}
}

View File

@ -0,0 +1,56 @@
//---------------------------------------------------------------------
// <copyright file="KnownAssemblyEntry.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics;
namespace System.Data.Metadata.Edm
{
internal sealed class KnownAssemblyEntry
{
private readonly AssemblyCacheEntry _cacheEntry;
private bool _referencedAssembliesAreLoaded;
private bool _seenWithEdmItemCollection;
internal KnownAssemblyEntry(AssemblyCacheEntry cacheEntry, bool seenWithEdmItemCollection)
{
Debug.Assert(cacheEntry != null, "Found a null cacheEntry");
_cacheEntry = cacheEntry;
_referencedAssembliesAreLoaded = false;
_seenWithEdmItemCollection = seenWithEdmItemCollection;
}
internal AssemblyCacheEntry CacheEntry
{
get { return _cacheEntry; }
}
public bool ReferencedAssembliesAreLoaded
{
get { return _referencedAssembliesAreLoaded; }
set { _referencedAssembliesAreLoaded = value; }
}
public bool SeenWithEdmItemCollection
{
get { return _seenWithEdmItemCollection; }
set { _seenWithEdmItemCollection = value; }
}
public bool HaveSeenInCompatibleContext(object loaderCookie, EdmItemCollection itemCollection)
{
// a new "context" is only when we have not seen this assembly with an itemCollection that is non-null
// and we now have a non-null itemCollection, and we are not already in AttributeLoader mode.
return SeenWithEdmItemCollection ||
itemCollection == null ||
ObjectItemAssemblyLoader.IsAttributeLoader(loaderCookie);
}
}
}

View File

@ -0,0 +1,75 @@
//---------------------------------------------------------------------
// <copyright file="ObjectItemLoadingSessionData.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
namespace System.Data.Metadata.Edm
{
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Diagnostics;
using System.Text;
internal class LoadMessageLogger
{
private Action<String> _logLoadMessage;
private Dictionary<EdmType, StringBuilder> _messages = new Dictionary<EdmType, StringBuilder>();
internal LoadMessageLogger(Action<String> logLoadMessage)
{
this._logLoadMessage = logLoadMessage;
}
internal void LogLoadMessage(string message, EdmType relatedType)
{
if (_logLoadMessage != null)
{
_logLoadMessage(message);
}
LogMessagesWithTypeInfo(message, relatedType);
}
internal string CreateErrorMessageWithTypeSpecificLoadLogs(string errorMessage, EdmType relatedType)
{
return new StringBuilder(errorMessage)
.AppendLine(this.GetTypeRelatedLogMessage(relatedType)).ToString();
}
private string GetTypeRelatedLogMessage(EdmType relatedType)
{
Debug.Assert(relatedType != null, "have to pass in a type to get the message");
if (this._messages.ContainsKey(relatedType))
{
return new StringBuilder()
.AppendLine()
.AppendLine(Strings.ExtraInfo)
.AppendLine(this._messages[relatedType].ToString()).ToString();
}
else
{
return string.Empty;
}
}
private void LogMessagesWithTypeInfo(string message, EdmType relatedType)
{
Debug.Assert(relatedType != null, "have to have a type with this message");
if (this._messages.ContainsKey(relatedType))
{
// if this type already contains loading message, append the new message to the end
this._messages[relatedType].AppendLine(message);
}
else
{
this._messages.Add(relatedType, new StringBuilder(message));
}
}
}
}

View File

@ -0,0 +1,73 @@
//---------------------------------------------------------------------
// <copyright file="LockedAssemblyCache.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
namespace System.Data.Metadata.Edm
{
internal class LockedAssemblyCache : IDisposable
{
private object _lockObject;
private Dictionary<Assembly, ImmutableAssemblyCacheEntry> _globalAssemblyCache;
internal LockedAssemblyCache(object lockObject, Dictionary<Assembly, ImmutableAssemblyCacheEntry> globalAssemblyCache)
{
_lockObject = lockObject;
_globalAssemblyCache = globalAssemblyCache;
#pragma warning disable 0618
//@
Monitor.Enter(_lockObject);
#pragma warning restore 0618
}
public void Dispose()
{
// Technically, calling GC.SuppressFinalize is not required because the class does not
// have a finalizer, but it does no harm, protects against the case where a finalizer is added
// in the future, and prevents an FxCop warning.
GC.SuppressFinalize(this);
Monitor.Exit(_lockObject);
_lockObject = null;
_globalAssemblyCache = null;
}
[Conditional("DEBUG")]
private void AssertLockedByThisThread()
{
bool entered = false;
Monitor.TryEnter(_lockObject, ref entered);
if (entered)
{
Monitor.Exit(_lockObject);
}
Debug.Assert(entered, "The cache is being accessed by a thread that isn't holding the lock");
}
internal bool TryGetValue(Assembly assembly, out ImmutableAssemblyCacheEntry cacheEntry)
{
AssertLockedByThisThread();
return _globalAssemblyCache.TryGetValue(assembly, out cacheEntry);
}
internal void Add(Assembly assembly, ImmutableAssemblyCacheEntry assemblyCacheEntry)
{
AssertLockedByThisThread();
_globalAssemblyCache.Add(assembly, assemblyCacheEntry);
}
internal void Clear()
{
AssertLockedByThisThread();
_globalAssemblyCache.Clear();
}
}
}

View File

@ -0,0 +1,90 @@
//---------------------------------------------------------------------
// <copyright file="MetadataAssemblyHelper.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Reflection;
using System.Collections.Generic;
using System.Diagnostics;
using System.Data.Common.Utils;
namespace System.Data.Metadata.Edm
{
internal static class MetadataAssemblyHelper
{
static byte [] EcmaPublicKeyToken = System.Data.EntityModel.SchemaObjectModel.ScalarType.ConvertToByteArray(AssemblyRef.EcmaPublicKey);
static byte [] MsPublicKeyToken = System.Data.EntityModel.SchemaObjectModel.ScalarType.ConvertToByteArray(AssemblyRef.MicrosoftPublicKey);
private static Memoizer<Assembly, bool> _filterAssemblyCacheByAssembly = new Memoizer<Assembly, bool>(MetadataAssemblyHelper.ComputeShouldFilterAssembly, EqualityComparer<Assembly>.Default);
internal static Assembly SafeLoadReferencedAssembly(AssemblyName assemblyName)
{
Assembly assembly = null;
try
{
assembly = Assembly.Load(assemblyName);
}
catch (System.IO.FileNotFoundException)
{
// See 552932: ObjectItemCollection: fails on referenced assemblies that are not available
}
return assembly;
}
private static bool ComputeShouldFilterAssembly(Assembly assembly)
{
AssemblyName assemblyName = new AssemblyName(assembly.FullName);
return ShouldFilterAssembly(assemblyName);
}
internal static bool ShouldFilterAssembly(Assembly assembly)
{
return _filterAssemblyCacheByAssembly.Evaluate(assembly);
}
/// <summary>Is the assembly and its referened assemblies not expected to have any metadata</summary>
private static bool ShouldFilterAssembly(AssemblyName assemblyName)
{
return (ArePublicKeyTokensEqual(assemblyName.GetPublicKeyToken(), EcmaPublicKeyToken) ||
ArePublicKeyTokensEqual(assemblyName.GetPublicKeyToken(), MsPublicKeyToken));
}
private static bool ArePublicKeyTokensEqual(byte [] left, byte [] right)
{
// some assemblies don't have public keys
if (left.Length != right.Length)
{
return false;
}
for (int i = 0; i < left.Length; i++)
{
if (left[i] != right[i])
{
return false;
}
}
return true;
}
internal static IEnumerable<Assembly> GetNonSystemReferencedAssemblies(Assembly assembly)
{
foreach (AssemblyName name in assembly.GetReferencedAssemblies())
{
if (!ShouldFilterAssembly(name))
{
Assembly referenceAssembly = SafeLoadReferencedAssembly(name);
if(referenceAssembly != null )
{
yield return referenceAssembly;
}
}
}
}
}
}

View File

@ -0,0 +1,32 @@
//---------------------------------------------------------------------
// <copyright file="MutableAssemblyCacheEntry.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Reflection;
namespace System.Data.Metadata.Edm
{
internal partial class MutableAssemblyCacheEntry : AssemblyCacheEntry
{
// types in "this" assembly
private readonly List<EdmType> _typesInAssembly = new List<EdmType>();
// other assemblies referenced by types we care about in "this" assembly
private readonly List<Assembly> _closureAssemblies = new List<Assembly>();
internal override IList<EdmType> TypesInAssembly
{
get { return _typesInAssembly; }
}
internal override IList<Assembly> ClosureAssemblies
{
get { return _closureAssemblies; }
}
}
}

View File

@ -0,0 +1,168 @@
//---------------------------------------------------------------------
// <copyright file="ObjectItemAssemblyLoader.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
namespace System.Data.Metadata.Edm
{
using System.Collections.Generic;
using System.Data.Entity;
using System.Diagnostics;
using System.Reflection;
internal abstract class ObjectItemAssemblyLoader
{
protected const BindingFlags PropertyReflectionBindingFlags = BindingFlags.DeclaredOnly |
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic;
private readonly ObjectItemLoadingSessionData _sessionData;
private Assembly _assembly;
private AssemblyCacheEntry _cacheEntry;
protected ObjectItemAssemblyLoader(Assembly assembly, AssemblyCacheEntry cacheEntry, ObjectItemLoadingSessionData sessionData)
{
_assembly = assembly;
_cacheEntry = cacheEntry;
_sessionData = sessionData;
}
internal virtual void Load()
{
AddToAssembliesLoaded();
LoadTypesFromAssembly();
AddToKnownAssemblies();
LoadClosureAssemblies();
}
protected abstract void AddToAssembliesLoaded();
protected abstract void LoadTypesFromAssembly();
protected virtual void LoadClosureAssemblies()
{
LoadAssemblies(CacheEntry.ClosureAssemblies, SessionData);
}
internal virtual void OnLevel1SessionProcessing() { }
internal virtual void OnLevel2SessionProcessing() { }
internal static ObjectItemAssemblyLoader CreateLoader(Assembly assembly, ObjectItemLoadingSessionData sessionData)
{
ImmutableAssemblyCacheEntry cacheEntry;
// KnownAssembly -> NoOp
// Inside the LockedAssemblyCache means it is an attribute based assembly -> Cachedassembly
// Inside the OcCache on EdmItemCollection -> cachedassembly
// If none of above, setup the LoaderFactory based on the current assembly and EdmItemCollection
if (sessionData.KnownAssemblies.Contains(assembly, sessionData.ObjectItemAssemblyLoaderFactory, sessionData.EdmItemCollection))
{
return new ObjectItemNoOpAssemblyLoader(assembly, sessionData);
}
else if (sessionData.LockedAssemblyCache.TryGetValue(assembly, out cacheEntry))
{
if (sessionData.ObjectItemAssemblyLoaderFactory == null)
{
if (cacheEntry.TypesInAssembly.Count != 0)
{
// we are loading based on attributes now
sessionData.ObjectItemAssemblyLoaderFactory = ObjectItemAttributeAssemblyLoader.Create;
}
// if types in assembly are 0, don't commit to any loader yet
}
else if (sessionData.ObjectItemAssemblyLoaderFactory != ObjectItemAttributeAssemblyLoader.Create)
{
// we were loading in convention mode, and ran into an assembly that can't be loaded by convention
// we know this because all cached assemblies are attribute based at the moment.
sessionData.EdmItemErrors.Add(new EdmItemError(Strings.Validator_OSpace_Convention_AttributeAssemblyReferenced(assembly.FullName), null));
}
return new ObjectItemCachedAssemblyLoader(assembly, cacheEntry, sessionData);
}
else if (sessionData.EdmItemCollection != null &&
sessionData.EdmItemCollection.ConventionalOcCache.TryGetConventionalOcCacheFromAssemblyCache(
assembly, out cacheEntry))
{
sessionData.ObjectItemAssemblyLoaderFactory = ObjectItemConventionAssemblyLoader.Create;
return new ObjectItemCachedAssemblyLoader(assembly, cacheEntry, sessionData);
}
else if (sessionData.ObjectItemAssemblyLoaderFactory == null)
{
if (ObjectItemAttributeAssemblyLoader.IsSchemaAttributePresent(assembly))
{
sessionData.ObjectItemAssemblyLoaderFactory = ObjectItemAttributeAssemblyLoader.Create;
}
else if (ObjectItemConventionAssemblyLoader.SessionContainsConventionParameters(sessionData))
{
sessionData.ObjectItemAssemblyLoaderFactory = ObjectItemConventionAssemblyLoader.Create;
}
}
if (sessionData.ObjectItemAssemblyLoaderFactory != null)
{
return sessionData.ObjectItemAssemblyLoaderFactory(assembly, sessionData);
}
return new ObjectItemNoOpAssemblyLoader(assembly, sessionData);
}
internal static bool IsAttributeLoader(object loaderCookie)
{
Debug.Assert(loaderCookie == null || loaderCookie is Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>, "Non loader cookie passed in");
return IsAttributeLoader(loaderCookie as Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader>);
}
internal static bool IsAttributeLoader(Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader> loaderFactory)
{
if (loaderFactory == null)
{
return false;
}
return loaderFactory == ObjectItemAttributeAssemblyLoader.Create;
}
internal static bool IsConventionLoader(Func<Assembly, ObjectItemLoadingSessionData, ObjectItemAssemblyLoader> loaderFactory)
{
if (loaderFactory == null)
{
return false;
}
return loaderFactory == ObjectItemConventionAssemblyLoader.Create;
}
protected virtual void AddToKnownAssemblies()
{
Debug.Assert(!_sessionData.KnownAssemblies.Contains(_assembly, SessionData.ObjectItemAssemblyLoaderFactory, _sessionData.EdmItemCollection), "This assembly must not be present in the list of known assemblies");
_sessionData.KnownAssemblies.Add(_assembly, new KnownAssemblyEntry(CacheEntry, SessionData.EdmItemCollection != null));
}
protected static void LoadAssemblies(IEnumerable<Assembly> assemblies, ObjectItemLoadingSessionData sessionData)
{
foreach (Assembly assembly in assemblies)
{
ObjectItemAssemblyLoader loader = ObjectItemAssemblyLoader.CreateLoader(assembly, sessionData);
loader.Load();
}
}
protected bool TryGetPrimitiveType(Type type, out PrimitiveType primitiveType)
{
return ClrProviderManifest.Instance.TryGetPrimitiveType(Nullable.GetUnderlyingType(type) ?? type, out primitiveType);
}
protected ObjectItemLoadingSessionData SessionData { get { return _sessionData; } }
protected Assembly SourceAssembly { get { return _assembly; } }
protected AssemblyCacheEntry CacheEntry { get { return _cacheEntry; } }
}
}

View File

@ -0,0 +1,43 @@
//---------------------------------------------------------------------
// <copyright file="ObjectItemCachedAssemblyLoader.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
namespace System.Data.Metadata.Edm
{
using System.Reflection;
internal sealed class ObjectItemCachedAssemblyLoader : ObjectItemAssemblyLoader
{
private new ImmutableAssemblyCacheEntry CacheEntry { get { return (ImmutableAssemblyCacheEntry)base.CacheEntry; } }
internal ObjectItemCachedAssemblyLoader(Assembly assembly, ImmutableAssemblyCacheEntry cacheEntry, ObjectItemLoadingSessionData sessionData)
: base(assembly, cacheEntry, sessionData)
{
}
protected override void AddToAssembliesLoaded()
{
// wasn't loaded, was pulled from cache instead
// so don't load it
}
protected override void LoadTypesFromAssembly()
{
foreach (EdmType type in CacheEntry.TypesInAssembly)
{
if (!SessionData.TypesInLoading.ContainsKey(type.Identity))
{
SessionData.TypesInLoading.Add(type.Identity, type);
}
}
}
}
}

View File

@ -0,0 +1,200 @@
//---------------------------------------------------------------------
// <copyright file="ObjectItemLoadingSessionData.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
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();
}
}
}
}

View File

@ -0,0 +1,38 @@
//---------------------------------------------------------------------
// <copyright file="ObjectItemNoOpAssemblyLoader.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Reflection;
namespace System.Data.Metadata.Edm
{
internal class ObjectItemNoOpAssemblyLoader : ObjectItemAssemblyLoader
{
internal ObjectItemNoOpAssemblyLoader(Assembly assembly, ObjectItemLoadingSessionData sessionData)
: base(assembly, new MutableAssemblyCacheEntry(), sessionData)
{ }
internal override void Load()
{
// don't do anything but make sure we know we have seen this assembly
if (!SessionData.KnownAssemblies.Contains(SourceAssembly, SessionData.ObjectItemAssemblyLoaderFactory, SessionData.EdmItemCollection))
{
AddToKnownAssemblies();
}
}
protected override void AddToAssembliesLoaded()
{
throw new NotImplementedException();
}
protected override void LoadTypesFromAssembly()
{
throw new NotImplementedException();
}
}
}