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
}
}