using System; using System.Collections.Generic; using System.Text; using System.Reflection; using ScriptNET.Runtime.Configuration; namespace ScriptNET.Runtime { public class BaseAssemblyManager : IAssemblyManager { #region Properties /// /// List of assemblies which are in use for the current moment. /// NOTE: This list may be changed during run-time (new assemblies may be added, some of them may be removed) /// protected readonly List WorkingAssemblies = new List(); /// /// Types cache. Contains all loaded types /// protected readonly Dictionary Types = new Dictionary(); /// /// Types by short names /// protected readonly Dictionary ShortTypes = new Dictionary(); /// /// Cache of Namesapces /// protected readonly Dictionary> Namespaces = new Dictionary>(); protected ScriptConfiguration Configuration { get; private set; } #endregion #region Initialization [Bindable(false)] public BaseAssemblyManager() { } [Bindable(false)] public virtual void Initialize(ScriptConfiguration Configuration) { this.Configuration = Configuration; FindAliasTypes(); LoadAssemblies(); ScanAssemblies(); } #endregion #region Methods /// /// Loads assemblies from configuration to memory and generate /// LoadedAssemblies list which will be scanned for types /// protected virtual void LoadAssemblies() { foreach (Reference reference in Configuration.References) { Assembly assembly = reference.Load(); if (WorkingAssemblies.Contains(assembly)) throw new NotSupportedException("Duplicate assembly in configuration"); WorkingAssemblies.Add(assembly); } } /// /// Scans types in Loaded assemblies /// protected virtual void ScanAssemblies() { foreach (Assembly assembly in WorkingAssemblies.ToArray()) AddAssembly(assembly); } protected virtual void RegisterType(Type type) { if (!Types.ContainsKey(type.FullName)) { Types.Add(type.FullName, type); //Register in namespaces if (!string.IsNullOrEmpty(type.Namespace)) { if (Namespaces.ContainsKey(type.Namespace)) { Namespaces[type.Namespace].Add(type); } else { List types = new List() { type }; Namespaces.Add(type.Namespace, types); } } } if (!ShortTypes.ContainsKey(type.Name)) { ShortTypes.Add(type.Name, type); } } protected virtual void UnRegisterType(Type type) { if (Types.ContainsKey(type.FullName)) { Types.Remove(type.FullName); //Clear namespace cache if (!string.IsNullOrEmpty(type.Namespace)) { List types = Namespaces[type.Namespace]; types.Remove(type); if (types.Count == 0) Namespaces.Remove(type.Namespace); } } if (ShortTypes.ContainsKey(type.Name)) { ShortTypes.Remove(type.Name); } //Remove all aliases if (ShortTypes.ContainsValue(type)) { List keysToRemove = new List(); foreach (KeyValuePair value in ShortTypes) { if (value.Value == type) keysToRemove.Add(value.Key); } foreach (string key in keysToRemove) ShortTypes.Remove(key); } } private void FindAliasTypes() { foreach (TypeXml typeXml in Configuration.Types) { Type type = RuntimeHost.GetNativeType(typeXml.QualifiedName); if (type == null) throw new NullReferenceException(string.Format("Type {0} is not found", typeXml.QualifiedName)); AddType(typeXml.Alias, type); } } protected virtual AssemblyHandlerEventArgs OnBeforeAddAssembly(Assembly assembly, Type type) { AssemblyHandlerEventArgs args = new AssemblyHandlerEventArgs (assembly, type); if (BeforeAddAssembly != null) BeforeAddAssembly.Invoke(this, args); return args; } public event EventHandler BeforeAddAssembly; protected virtual AssemblyHandlerEventArgs OnBeforeAddType(Assembly assembly, Type type) { AssemblyHandlerEventArgs args = new AssemblyHandlerEventArgs(assembly, type); if (BeforeAddType != null) BeforeAddType.Invoke(this, args); return args; } public event EventHandler BeforeAddType; #endregion #region Public Interface public virtual void AddAssembly(Assembly assembly) { if (OnBeforeAddAssembly(assembly, null).Cancel) { WorkingAssemblies.Remove(assembly); return; } if (!WorkingAssemblies.Contains(assembly)) { WorkingAssemblies.Add(assembly); } foreach (Type type in assembly.GetTypes()) { if (!type.IsPublic) continue; if (OnBeforeAddType(assembly, type).Cancel) continue; RegisterType(type); } } public virtual void RemoveAssembly(Assembly assembly) { if (!WorkingAssemblies.Contains(assembly)) return; foreach (Type type in assembly.GetTypes()) { if (!type.IsPublic) continue; UnRegisterType(type); } WorkingAssemblies.Remove(assembly); } /// /// Returns type by given name /// /// Short, Alias or FullType name /// Type /// /// If type not found /// public Type GetType(string name) { if (ShortTypes.ContainsKey(name)) return ShortTypes[name]; if (Types.ContainsKey(name)) return Types[name]; throw new ScriptException(string.Format("Type with given name \"{0}\"is not found", name)); } public bool HasType(string name) { return ShortTypes.ContainsKey(name) || Types.ContainsKey(name); } /// /// Adds type to a manager /// /// /// public void AddType(string alias, Type type) { RuntimeHost.Lock(); try { if (ShortTypes.ContainsKey(alias)) { ShortTypes[alias] = type; } else { ShortTypes.Add(alias, type); } } finally { RuntimeHost.UnLock(); } } public bool HasNamespace(string name) { return Namespaces.ContainsKey(name); } #endregion #region IDisposable Members [Bindable(false)] public virtual void Dispose() { ShortTypes.Clear(); Types.Clear(); } #endregion } }