using System; using System.IO; using System.Reflection; using JD.Kernel.Classes; using JD.Kernel.StaticHelpers; using JD.LogService; using JD.TeaBoxAddinSystem.Bootstrap; namespace JD.TeaBoxAddinSystem.Addins.Description { /// /// A runtime wraps a lazy-loaded assembly, referenced by one or more addin(s). /// /// /// Assemblies can be referenced in a number of different ways: /// ":AssemblyName" will load AssemblyName with Assembly.Load. /// "AssemblyName" will load AssemblyName with Assembly.LoadFrom (using an hint path). /// public sealed class RuntimeAssembly { #region Variables private Reference m_assembly; private readonly string m_assemblyName; #endregion #region Constructors /// /// Constructor /// /// Assembly Name /// A hint path for the Assembly location, if needed. public RuntimeAssembly(string assemblyName, string hintPath) { Throw.IfEmpty(assemblyName, "assemblyName"); m_assemblyName = assemblyName; m_assembly = ThreadSafeReference.FromDelegate(() => LoadAssembly(assemblyName, hintPath)); } /// /// Alternative Constructor taking an already loaded assembly. /// /// The assembly to wrap public RuntimeAssembly(Assembly assembly) { Throw.IfNull(assembly, "assembly"); m_assembly = Reference.FromValue(assembly); } #endregion #region Properties /// /// Returns whether the underlying assembly has been loaded yet. /// public bool IsLoaded { get { return m_assembly.IsInitialized; } } /// /// Returns the name of the assembly to be loaded. /// public string AssemblyName { get { if (IsLoaded) { return m_assembly.Value.FullName; } return m_assemblyName; } } /// /// Gets the assembly referenced by this Runtime, loading it first if needed. /// public Assembly Assembly { get { return m_assembly.Value; } } #endregion #region Methods private Assembly LoadAssembly(string assemblyName, string hintPath) { AddinManager.Log(new Message("Loading Addin Assembly {0}.", assemblyName) { Importance = MessageImportance.Low }); foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (IsCurrentAssembly(assembly)) { return assembly; } } try { if (assemblyName[0] == ':') { m_assembly = Assembly.Load(assemblyName.Substring(1)); } else { if (hintPath == null) { m_assembly = Assembly.LoadFrom(assemblyName); } else { string file = FindExistingPath(Path.Combine(hintPath, assemblyName), Path.Combine(Path.GetDirectoryName(hintPath), assemblyName)); return Assembly.LoadFrom(file); } } } catch (FileNotFoundException ex) { AddinManager.Log(new Error(LogCategory.Error, "The Addin Assembly {0} could not be loaded: {1}", assemblyName, ex.Message)); throw; } catch (FileLoadException ex) { AddinManager.Log(new Error(LogCategory.Error, "The Addin Assembly {0} could not be loaded: {1}", assemblyName, ex.Message)); throw; } return null; } private bool IsCurrentAssembly(Assembly assembly) { // Compares without the extension first since assembly.Location may fail if assembly is a generated assembly. return assembly.GetName().Name == Path.GetFileNameWithoutExtension(AssemblyName) && Path.GetFileName(assembly.Location) == AssemblyName; } /// /// Takes the alternative path if the first one does not exists. /// /// /// /// private static string FindExistingPath(string path, string alternative) { try { if (!File.Exists(path) && File.Exists(alternative)) return alternative; } catch { } return path; } /// /// Creates an instance of an object whose type is defined in this . /// /// The full name of the type to create. /// Arguments to be passed to the constructor of the object. /// The created object, or null if it could not be created. public object CreateInstance(string typeName, params object[] args) { if (Assembly == null || string.IsNullOrEmpty(typeName)) { return null; } return Assembly.CreateInstance(typeName, true, BindingFlags.Default, null, args, System.Globalization.CultureInfo.CurrentCulture, null); } /// /// Gets a specific type within this . /// /// Full name of the type. /// A corresponding to the given type, or null if not found. public Type GetType(string typeName) { if (Assembly == null || string.IsNullOrEmpty(typeName)) { return null; } return Assembly.GetType(typeName, false); } /// /// Overriden. /// /// public override string ToString() { return $"[Runtime: Assembly={AssemblyName}]"; } #endregion } }